...

Source file src/github.com/sassoftware/relic/lib/x509tools/printcert.go

Documentation: github.com/sassoftware/relic/lib/x509tools

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package x509tools
    18  
    19  import (
    20  	"crypto/ecdsa"
    21  	"crypto/rsa"
    22  	"crypto/x509"
    23  	"encoding/asn1"
    24  	"fmt"
    25  	"io"
    26  	"time"
    27  )
    28  
    29  var keyUsageNames = map[x509.KeyUsage]string{
    30  	x509.KeyUsageDigitalSignature:  "digitalSignature",
    31  	x509.KeyUsageContentCommitment: "nonRepudiation",
    32  	x509.KeyUsageKeyEncipherment:   "keyEncipherment",
    33  	x509.KeyUsageDataEncipherment:  "dataEncipherment",
    34  	x509.KeyUsageKeyAgreement:      "keyAgreement",
    35  	x509.KeyUsageCertSign:          "keyCertSign",
    36  	x509.KeyUsageCRLSign:           "cRLSign",
    37  	x509.KeyUsageEncipherOnly:      "encipherOnly",
    38  	x509.KeyUsageDecipherOnly:      "decipherOnly",
    39  }
    40  
    41  var extKeyUsageNames = map[x509.ExtKeyUsage]string{
    42  	x509.ExtKeyUsageAny:             "any",
    43  	x509.ExtKeyUsageServerAuth:      "serverAuth",
    44  	x509.ExtKeyUsageClientAuth:      "clientAuth",
    45  	x509.ExtKeyUsageCodeSigning:     "codeSigning",
    46  	x509.ExtKeyUsageEmailProtection: "emailProtection",
    47  	x509.ExtKeyUsageIPSECEndSystem:  "ipsecEndSystem",
    48  	x509.ExtKeyUsageIPSECTunnel:     "ipsecTunnel",
    49  	x509.ExtKeyUsageIPSECUser:       "ipsecUser",
    50  	x509.ExtKeyUsageTimeStamping:    "timeStamping",
    51  	x509.ExtKeyUsageOCSPSigning:     "OCSPSigning",
    52  
    53  	x509.ExtKeyUsageMicrosoftServerGatedCrypto:     "msServerGatedCrypto",
    54  	x509.ExtKeyUsageNetscapeServerGatedCrypto:      "nsServerGatedCrypto",
    55  	x509.ExtKeyUsageMicrosoftCommercialCodeSigning: "msCodeCom",
    56  	x509.ExtKeyUsageMicrosoftKernelCodeSigning:     "msKernCode",
    57  }
    58  
    59  var knownExtensions = []asn1.ObjectIdentifier{
    60  	asn1.ObjectIdentifier{2, 5, 29, 14},               // oidExtensionSubjectKeyId
    61  	asn1.ObjectIdentifier{2, 5, 29, 15},               // oidExtensionKeyUsage
    62  	asn1.ObjectIdentifier{2, 5, 29, 37},               // oidExtensionExtendedKeyUsage
    63  	asn1.ObjectIdentifier{2, 5, 29, 35},               // oidExtensionAuthorityKeyId
    64  	asn1.ObjectIdentifier{2, 5, 29, 19},               // oidExtensionBasicConstraints
    65  	asn1.ObjectIdentifier{2, 5, 29, 17},               // oidExtensionSubjectAltName
    66  	asn1.ObjectIdentifier{2, 5, 29, 32},               // oidExtensionCertificatePolicies
    67  	asn1.ObjectIdentifier{2, 5, 29, 30},               // oidExtensionNameConstraints
    68  	asn1.ObjectIdentifier{2, 5, 29, 31},               // oidExtensionCRLDistributionPoints
    69  	asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 1},  // oidExtensionAuthorityInfoAccess
    70  	asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1}, // oidAuthorityInfoAccessOcsp
    71  	asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2}, // oidAuthorityInfoAccessIssuers
    72  }
    73  
    74  // FprintCertificate formats a certificate for display
    75  func FprintCertificate(w io.Writer, cert *x509.Certificate) {
    76  	fmt.Fprintln(w, "Version:", cert.Version)
    77  	if cert.SerialNumber.BitLen() > 63 {
    78  		fmt.Fprintf(w, "Serial:  0x%x\n", cert.SerialNumber)
    79  	} else {
    80  		fmt.Fprintf(w, "Serial:  %d (0x%x)\n", cert.SerialNumber, cert.SerialNumber)
    81  	}
    82  	fmt.Fprintln(w, "Subject:", FormatSubject(cert))
    83  	fmt.Fprintln(w, "Issuer: ", FormatIssuer(cert))
    84  	fmt.Fprintln(w, "Valid:  ", cert.NotBefore)
    85  	fmt.Fprintln(w, "Expires:", cert.NotAfter)
    86  	fmt.Fprintln(w, "Period: ", subDate(cert.NotAfter, cert.NotBefore))
    87  	switch k := cert.PublicKey.(type) {
    88  	case *rsa.PublicKey:
    89  		n := fmt.Sprintf("%x", k.N)
    90  		fmt.Fprintf(w, "Pub key: RSA bits=%d e=%d n=%s...%s\n", k.N.BitLen(), k.E, n[:8], n[len(n)-8:])
    91  	case *ecdsa.PublicKey:
    92  		p := k.Params()
    93  		x := fmt.Sprintf("%x", k.X)
    94  		y := fmt.Sprintf("%x", k.Y)
    95  		fmt.Fprintf(w, "Public key: ECDSA bits=%d name=%s x=%s... y=...%s\n", p.BitSize, p.Name, x[:8], y[len(y)-8:])
    96  	default:
    97  		fmt.Fprintf(w, "Public key: %T\n", k)
    98  	}
    99  	fmt.Fprintln(w, "Sig alg:", cert.SignatureAlgorithm)
   100  	fmt.Fprintln(w, "Extensions:")
   101  	// subject alternate names
   102  	printSAN(w, cert)
   103  	// basic constraints
   104  	if cert.BasicConstraintsValid {
   105  		cons := fmt.Sprintf("isCA=%t", cert.IsCA)
   106  		if cert.MaxPathLenZero {
   107  			cons += " MaxPathLen=0"
   108  		} else if cert.MaxPathLen > 0 {
   109  			cons += fmt.Sprintf(" MaxPathLen=%d", cert.MaxPathLen)
   110  		}
   111  		fmt.Fprintln(w, "  Basic constraints: "+cons)
   112  	}
   113  	// Name constraints
   114  	printNameConstraints(w, cert)
   115  	// key usage
   116  	usage := ""
   117  	for n, name := range keyUsageNames {
   118  		if cert.KeyUsage&n != 0 {
   119  			usage += ", " + name
   120  		}
   121  	}
   122  	if usage != "" {
   123  		fmt.Fprintln(w, "  Key Usage:", usage[2:])
   124  	}
   125  	// extended key usage
   126  	usage = ""
   127  	for _, u := range cert.ExtKeyUsage {
   128  		name := extKeyUsageNames[u]
   129  		if name == "" {
   130  			name = fmt.Sprintf("%d", u)
   131  		}
   132  		usage += ", " + name
   133  	}
   134  	for _, u := range cert.UnknownExtKeyUsage {
   135  		usage += ", " + u.String()
   136  	}
   137  	if usage != "" {
   138  		fmt.Fprintln(w, "  Extended key usage:", usage[2:])
   139  	}
   140  	// keyids
   141  	if len(cert.SubjectKeyId) != 0 {
   142  		fmt.Fprintf(w, "  Subject key ID: %x\n", cert.SubjectKeyId)
   143  	}
   144  	if len(cert.AuthorityKeyId) != 0 {
   145  		fmt.Fprintf(w, "  Authority key ID: %x\n", cert.AuthorityKeyId)
   146  	}
   147  	// authority info
   148  	if len(cert.OCSPServer) != 0 {
   149  		fmt.Fprintln(w, "  OCSP Servers:")
   150  		for _, s := range cert.OCSPServer {
   151  			fmt.Fprintln(w, "   ", s)
   152  		}
   153  	}
   154  	if len(cert.IssuingCertificateURL) != 0 {
   155  		fmt.Fprintln(w, "  Issuing authority URLs:")
   156  		for _, s := range cert.IssuingCertificateURL {
   157  			fmt.Fprintln(w, "   ", s)
   158  		}
   159  	}
   160  	// CRL
   161  	if len(cert.CRLDistributionPoints) != 0 {
   162  		fmt.Fprintln(w, "  CRL Distribution Points:")
   163  		for _, s := range cert.CRLDistributionPoints {
   164  			fmt.Fprintln(w, "   ", s)
   165  		}
   166  	}
   167  	// Policy IDs
   168  	if len(cert.PolicyIdentifiers) != 0 {
   169  		fmt.Fprintln(w, "  Policy Identifiers:")
   170  		for _, s := range cert.PolicyIdentifiers {
   171  			fmt.Fprintln(w, "   ", s.String())
   172  		}
   173  	}
   174  	// Other
   175  	for _, ex := range cert.Extensions {
   176  		if knownExtension(ex.Id) {
   177  			continue
   178  		}
   179  		critical := ""
   180  		if ex.Critical {
   181  			critical = " (critical)"
   182  		}
   183  		fmt.Fprintf(w, "  Extension %s%s: %x\n", ex.Id, critical, ex.Value)
   184  	}
   185  }
   186  
   187  func knownExtension(id asn1.ObjectIdentifier) bool {
   188  	for _, known := range knownExtensions {
   189  		if known.Equal(id) {
   190  			return true
   191  		}
   192  	}
   193  	return false
   194  }
   195  
   196  const (
   197  	durYear  = 8766 * time.Hour
   198  	yearSlop = 2 * 24 * time.Hour
   199  )
   200  
   201  // calculate duration using calendar dates
   202  func subDate(end, start time.Time) string {
   203  	approx := "~"
   204  	dur := end.Sub(start)
   205  	switch {
   206  	case dur >= durYear-yearSlop:
   207  		years := int((dur + yearSlop) / durYear)
   208  		if start.AddDate(years, 0, 0).Equal(end) {
   209  			approx = ""
   210  		}
   211  		if years > 1 {
   212  			return fmt.Sprintf("%s%d years", approx, years)
   213  		}
   214  		return approx + "1 year"
   215  	case dur >= 24*time.Hour:
   216  		days := int(dur / (24 * time.Hour))
   217  		if start.AddDate(0, 0, days).Equal(end) {
   218  			approx = ""
   219  		}
   220  		if days > 1 {
   221  			return fmt.Sprintf("%s%d days", approx, days)
   222  		}
   223  		return approx + "1 day"
   224  	default:
   225  		return dur.String()
   226  	}
   227  }
   228  
   229  func printSAN(w io.Writer, cert *x509.Certificate) {
   230  	if len(cert.DNSNames) != 0 || len(cert.EmailAddresses) != 0 || len(cert.IPAddresses) != 0 || len(cert.URIs) != 0 {
   231  		fmt.Fprintln(w, "  Subject alternate names:")
   232  		for _, s := range cert.DNSNames {
   233  			fmt.Fprintln(w, "    dns:"+s)
   234  		}
   235  		for _, s := range cert.EmailAddresses {
   236  			fmt.Fprintln(w, "    email:"+s)
   237  		}
   238  		for _, s := range cert.IPAddresses {
   239  			fmt.Fprintln(w, "    ip:"+s.String())
   240  		}
   241  		for _, s := range cert.URIs {
   242  			fmt.Fprintln(w, "    uri:"+s.String())
   243  		}
   244  	}
   245  }
   246  
   247  func printNameConstraints(w io.Writer, cert *x509.Certificate) {
   248  	if len(cert.PermittedDNSDomains) != 0 || len(cert.ExcludedDNSDomains) != 0 || len(cert.PermittedIPRanges) != 0 || len(cert.ExcludedIPRanges) != 0 || len(cert.PermittedEmailAddresses) != 0 || len(cert.ExcludedEmailAddresses) != 0 || len(cert.PermittedURIDomains) != 0 || len(cert.ExcludedURIDomains) != 0 {
   249  		fmt.Fprintln(w, "  Name constraints:")
   250  		for _, s := range cert.PermittedDNSDomains {
   251  			fmt.Fprintln(w, "     Permitted DNS domain:", s)
   252  		}
   253  		for _, s := range cert.ExcludedDNSDomains {
   254  			fmt.Fprintln(w, "     Excluded DNS domain:", s)
   255  		}
   256  		for _, s := range cert.PermittedIPRanges {
   257  			fmt.Fprintln(w, "     Permitted IP range:", s)
   258  		}
   259  		for _, s := range cert.ExcludedIPRanges {
   260  			fmt.Fprintln(w, "     Excluded IP range:", s)
   261  		}
   262  		for _, s := range cert.PermittedEmailAddresses {
   263  			fmt.Fprintln(w, "     Permitted Email Addresses:", s)
   264  		}
   265  		for _, s := range cert.ExcludedEmailAddresses {
   266  			fmt.Fprintln(w, "     Excluded Email Addresses:", s)
   267  		}
   268  		for _, s := range cert.PermittedURIDomains {
   269  			fmt.Fprintln(w, "     Permitted URI domain:", s)
   270  		}
   271  		for _, s := range cert.ExcludedURIDomains {
   272  			fmt.Fprintln(w, "     Excluded URI domain:", s)
   273  		}
   274  	}
   275  }
   276  

View as plain text