...

Source file src/github.com/google/certificate-transparency-go/x509util/x509util.go

Documentation: github.com/google/certificate-transparency-go/x509util

     1  // Copyright 2016 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package x509util includes utility code for working with X.509
    16  // certificates from the x509 package.
    17  package x509util
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/dsa"
    22  	"crypto/ecdsa"
    23  	"crypto/elliptic"
    24  	"crypto/rsa"
    25  	"encoding/base64"
    26  	"encoding/hex"
    27  	"encoding/pem"
    28  	"errors"
    29  	"fmt"
    30  	"net"
    31  	"strconv"
    32  
    33  	ct "github.com/google/certificate-transparency-go"
    34  	"github.com/google/certificate-transparency-go/asn1"
    35  	"github.com/google/certificate-transparency-go/gossip/minimal/x509ext"
    36  	"github.com/google/certificate-transparency-go/tls"
    37  	"github.com/google/certificate-transparency-go/x509"
    38  	"github.com/google/certificate-transparency-go/x509/pkix"
    39  )
    40  
    41  // OIDForStandardExtension indicates whether oid identifies a standard extension.
    42  // Standard extensions are listed in RFC 5280 (and other RFCs).
    43  func OIDForStandardExtension(oid asn1.ObjectIdentifier) bool {
    44  	if oid.Equal(x509.OIDExtensionSubjectKeyId) ||
    45  		oid.Equal(x509.OIDExtensionKeyUsage) ||
    46  		oid.Equal(x509.OIDExtensionExtendedKeyUsage) ||
    47  		oid.Equal(x509.OIDExtensionAuthorityKeyId) ||
    48  		oid.Equal(x509.OIDExtensionBasicConstraints) ||
    49  		oid.Equal(x509.OIDExtensionSubjectAltName) ||
    50  		oid.Equal(x509.OIDExtensionCertificatePolicies) ||
    51  		oid.Equal(x509.OIDExtensionNameConstraints) ||
    52  		oid.Equal(x509.OIDExtensionCRLDistributionPoints) ||
    53  		oid.Equal(x509.OIDExtensionIssuerAltName) ||
    54  		oid.Equal(x509.OIDExtensionSubjectDirectoryAttributes) ||
    55  		oid.Equal(x509.OIDExtensionInhibitAnyPolicy) ||
    56  		oid.Equal(x509.OIDExtensionPolicyConstraints) ||
    57  		oid.Equal(x509.OIDExtensionPolicyMappings) ||
    58  		oid.Equal(x509.OIDExtensionFreshestCRL) ||
    59  		oid.Equal(x509.OIDExtensionSubjectInfoAccess) ||
    60  		oid.Equal(x509.OIDExtensionAuthorityInfoAccess) ||
    61  		oid.Equal(x509.OIDExtensionIPPrefixList) ||
    62  		oid.Equal(x509.OIDExtensionASList) ||
    63  		oid.Equal(x509.OIDExtensionCTPoison) ||
    64  		oid.Equal(x509.OIDExtensionCTSCT) {
    65  		return true
    66  	}
    67  	return false
    68  }
    69  
    70  // OIDInExtensions checks whether the extension identified by oid is present in extensions
    71  // and returns how many times it occurs together with an indication of whether any of them
    72  // are marked critical.
    73  func OIDInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) (int, bool) {
    74  	count := 0
    75  	critical := false
    76  	for _, ext := range extensions {
    77  		if ext.Id.Equal(oid) {
    78  			count++
    79  			if ext.Critical {
    80  				critical = true
    81  			}
    82  		}
    83  	}
    84  	return count, critical
    85  }
    86  
    87  // String formatting for various X.509/ASN.1 types
    88  func bitStringToString(b asn1.BitString) string { // nolint:deadcode,unused
    89  	result := hex.EncodeToString(b.Bytes)
    90  	bitsLeft := b.BitLength % 8
    91  	if bitsLeft != 0 {
    92  		result += " (" + strconv.Itoa(8-bitsLeft) + " unused bits)"
    93  	}
    94  	return result
    95  }
    96  
    97  func publicKeyAlgorithmToString(algo x509.PublicKeyAlgorithm) string {
    98  	// Use OpenSSL-compatible strings for the algorithms.
    99  	switch algo {
   100  	case x509.RSA:
   101  		return "rsaEncryption"
   102  	case x509.DSA:
   103  		return "dsaEncryption"
   104  	case x509.ECDSA:
   105  		return "id-ecPublicKey"
   106  	default:
   107  		return strconv.Itoa(int(algo))
   108  	}
   109  }
   110  
   111  // appendHexData adds a hex dump of binary data to buf, with line breaks
   112  // after each set of count bytes, and with each new line prefixed with the
   113  // given prefix.
   114  func appendHexData(buf *bytes.Buffer, data []byte, count int, prefix string) {
   115  	for ii, b := range data {
   116  		if ii%count == 0 {
   117  			if ii > 0 {
   118  				buf.WriteString("\n")
   119  			}
   120  			buf.WriteString(prefix)
   121  		}
   122  		buf.WriteString(fmt.Sprintf("%02x:", b))
   123  	}
   124  }
   125  
   126  func curveOIDToString(oid asn1.ObjectIdentifier) (t string, bitlen int) {
   127  	switch {
   128  	case oid.Equal(x509.OIDNamedCurveP224):
   129  		return "secp224r1", 224
   130  	case oid.Equal(x509.OIDNamedCurveP256):
   131  		return "prime256v1", 256
   132  	case oid.Equal(x509.OIDNamedCurveP384):
   133  		return "secp384r1", 384
   134  	case oid.Equal(x509.OIDNamedCurveP521):
   135  		return "secp521r1", 521
   136  	case oid.Equal(x509.OIDNamedCurveP192):
   137  		return "secp192r1", 192
   138  	}
   139  	return fmt.Sprintf("%v", oid), -1
   140  }
   141  
   142  func publicKeyToString(_ x509.PublicKeyAlgorithm, pub interface{}) string {
   143  	var buf bytes.Buffer
   144  	switch pub := pub.(type) {
   145  	case *rsa.PublicKey:
   146  		bitlen := pub.N.BitLen()
   147  		buf.WriteString(fmt.Sprintf("                Public Key: (%d bit)\n", bitlen))
   148  		buf.WriteString("                Modulus:\n")
   149  		data := pub.N.Bytes()
   150  		appendHexData(&buf, data, 15, "                    ")
   151  		buf.WriteString("\n")
   152  		buf.WriteString(fmt.Sprintf("                Exponent: %d (0x%x)", pub.E, pub.E))
   153  	case *dsa.PublicKey:
   154  		buf.WriteString("                pub:\n")
   155  		appendHexData(&buf, pub.Y.Bytes(), 15, "                    ")
   156  		buf.WriteString("\n")
   157  		buf.WriteString("                P:\n")
   158  		appendHexData(&buf, pub.P.Bytes(), 15, "                    ")
   159  		buf.WriteString("\n")
   160  		buf.WriteString("                Q:\n")
   161  		appendHexData(&buf, pub.Q.Bytes(), 15, "                    ")
   162  		buf.WriteString("\n")
   163  		buf.WriteString("                G:\n")
   164  		appendHexData(&buf, pub.G.Bytes(), 15, "                    ")
   165  	case *ecdsa.PublicKey:
   166  		data := elliptic.Marshal(pub.Curve, pub.X, pub.Y)
   167  		oid, ok := x509.OIDFromNamedCurve(pub.Curve)
   168  		if !ok {
   169  			return "                <unsupported elliptic curve>"
   170  		}
   171  		oidname, bitlen := curveOIDToString(oid)
   172  		buf.WriteString(fmt.Sprintf("                Public Key: (%d bit)\n", bitlen))
   173  		buf.WriteString("                pub:\n")
   174  		appendHexData(&buf, data, 15, "                    ")
   175  		buf.WriteString("\n")
   176  		buf.WriteString(fmt.Sprintf("                ASN1 OID: %s", oidname))
   177  	default:
   178  		buf.WriteString(fmt.Sprintf("%v", pub))
   179  	}
   180  	return buf.String()
   181  }
   182  
   183  func commaAppend(buf *bytes.Buffer, s string) {
   184  	if buf.Len() > 0 {
   185  		buf.WriteString(", ")
   186  	}
   187  	buf.WriteString(s)
   188  }
   189  
   190  func keyUsageToString(k x509.KeyUsage) string {
   191  	var buf bytes.Buffer
   192  	if k&x509.KeyUsageDigitalSignature != 0 {
   193  		commaAppend(&buf, "Digital Signature")
   194  	}
   195  	if k&x509.KeyUsageContentCommitment != 0 {
   196  		commaAppend(&buf, "Content Commitment")
   197  	}
   198  	if k&x509.KeyUsageKeyEncipherment != 0 {
   199  		commaAppend(&buf, "Key Encipherment")
   200  	}
   201  	if k&x509.KeyUsageDataEncipherment != 0 {
   202  		commaAppend(&buf, "Data Encipherment")
   203  	}
   204  	if k&x509.KeyUsageKeyAgreement != 0 {
   205  		commaAppend(&buf, "Key Agreement")
   206  	}
   207  	if k&x509.KeyUsageCertSign != 0 {
   208  		commaAppend(&buf, "Certificate Signing")
   209  	}
   210  	if k&x509.KeyUsageCRLSign != 0 {
   211  		commaAppend(&buf, "CRL Signing")
   212  	}
   213  	if k&x509.KeyUsageEncipherOnly != 0 {
   214  		commaAppend(&buf, "Encipher Only")
   215  	}
   216  	if k&x509.KeyUsageDecipherOnly != 0 {
   217  		commaAppend(&buf, "Decipher Only")
   218  	}
   219  	return buf.String()
   220  }
   221  
   222  func extKeyUsageToString(u x509.ExtKeyUsage) string {
   223  	switch u {
   224  	case x509.ExtKeyUsageAny:
   225  		return "Any"
   226  	case x509.ExtKeyUsageServerAuth:
   227  		return "TLS Web server authentication"
   228  	case x509.ExtKeyUsageClientAuth:
   229  		return "TLS Web client authentication"
   230  	case x509.ExtKeyUsageCodeSigning:
   231  		return "Signing of executable code"
   232  	case x509.ExtKeyUsageEmailProtection:
   233  		return "Email protection"
   234  	case x509.ExtKeyUsageIPSECEndSystem:
   235  		return "IPSEC end system"
   236  	case x509.ExtKeyUsageIPSECTunnel:
   237  		return "IPSEC tunnel"
   238  	case x509.ExtKeyUsageIPSECUser:
   239  		return "IPSEC user"
   240  	case x509.ExtKeyUsageTimeStamping:
   241  		return "Time stamping"
   242  	case x509.ExtKeyUsageOCSPSigning:
   243  		return "OCSP signing"
   244  	case x509.ExtKeyUsageMicrosoftServerGatedCrypto:
   245  		return "Microsoft server gated cryptography"
   246  	case x509.ExtKeyUsageNetscapeServerGatedCrypto:
   247  		return "Netscape server gated cryptography"
   248  	case x509.ExtKeyUsageCertificateTransparency:
   249  		return "Certificate transparency"
   250  	default:
   251  		return "Unknown"
   252  	}
   253  }
   254  
   255  func attributeOIDToString(oid asn1.ObjectIdentifier) string { // nolint:deadcode,unused
   256  	switch {
   257  	case oid.Equal(pkix.OIDCountry):
   258  		return "Country"
   259  	case oid.Equal(pkix.OIDOrganization):
   260  		return "Organization"
   261  	case oid.Equal(pkix.OIDOrganizationalUnit):
   262  		return "OrganizationalUnit"
   263  	case oid.Equal(pkix.OIDCommonName):
   264  		return "CommonName"
   265  	case oid.Equal(pkix.OIDSerialNumber):
   266  		return "SerialNumber"
   267  	case oid.Equal(pkix.OIDLocality):
   268  		return "Locality"
   269  	case oid.Equal(pkix.OIDProvince):
   270  		return "Province"
   271  	case oid.Equal(pkix.OIDStreetAddress):
   272  		return "StreetAddress"
   273  	case oid.Equal(pkix.OIDPostalCode):
   274  		return "PostalCode"
   275  	case oid.Equal(pkix.OIDPseudonym):
   276  		return "Pseudonym"
   277  	case oid.Equal(pkix.OIDTitle):
   278  		return "Title"
   279  	case oid.Equal(pkix.OIDDnQualifier):
   280  		return "DnQualifier"
   281  	case oid.Equal(pkix.OIDName):
   282  		return "Name"
   283  	case oid.Equal(pkix.OIDSurname):
   284  		return "Surname"
   285  	case oid.Equal(pkix.OIDGivenName):
   286  		return "GivenName"
   287  	case oid.Equal(pkix.OIDInitials):
   288  		return "Initials"
   289  	case oid.Equal(pkix.OIDGenerationQualifier):
   290  		return "GenerationQualifier"
   291  	default:
   292  		return oid.String()
   293  	}
   294  }
   295  
   296  // NameToString creates a string description of a pkix.Name object.
   297  func NameToString(name pkix.Name) string {
   298  	var result bytes.Buffer
   299  	addSingle := func(prefix, item string) {
   300  		if len(item) == 0 {
   301  			return
   302  		}
   303  		commaAppend(&result, prefix)
   304  		result.WriteString(item)
   305  	}
   306  	addList := func(prefix string, items []string) {
   307  		for _, item := range items {
   308  			addSingle(prefix, item)
   309  		}
   310  	}
   311  	addList("C=", name.Country)
   312  	addList("O=", name.Organization)
   313  	addList("OU=", name.OrganizationalUnit)
   314  	addList("L=", name.Locality)
   315  	addList("ST=", name.Province)
   316  	addList("streetAddress=", name.StreetAddress)
   317  	addList("postalCode=", name.PostalCode)
   318  	addSingle("serialNumber=", name.SerialNumber)
   319  	addSingle("CN=", name.CommonName)
   320  	for _, atv := range name.Names {
   321  		value, ok := atv.Value.(string)
   322  		if !ok {
   323  			continue
   324  		}
   325  		t := atv.Type
   326  		// All of the defined attribute OIDs are of the form 2.5.4.N, and OIDAttribute is
   327  		// the 2.5.4 prefix ('id-at' in RFC 5280).
   328  		if len(t) == 4 && t[0] == pkix.OIDAttribute[0] && t[1] == pkix.OIDAttribute[1] && t[2] == pkix.OIDAttribute[2] {
   329  			// OID is 'id-at N', so check the final value to figure out which attribute.
   330  			switch t[3] {
   331  			case pkix.OIDCommonName[3], pkix.OIDSerialNumber[3], pkix.OIDCountry[3], pkix.OIDLocality[3], pkix.OIDProvince[3],
   332  				pkix.OIDStreetAddress[3], pkix.OIDOrganization[3], pkix.OIDOrganizationalUnit[3], pkix.OIDPostalCode[3]:
   333  				continue // covered by explicit fields
   334  			case pkix.OIDPseudonym[3]:
   335  				addSingle("pseudonym=", value)
   336  				continue
   337  			case pkix.OIDTitle[3]:
   338  				addSingle("title=", value)
   339  				continue
   340  			case pkix.OIDDnQualifier[3]:
   341  				addSingle("dnQualifier=", value)
   342  				continue
   343  			case pkix.OIDName[3]:
   344  				addSingle("name=", value)
   345  				continue
   346  			case pkix.OIDSurname[3]:
   347  				addSingle("surname=", value)
   348  				continue
   349  			case pkix.OIDGivenName[3]:
   350  				addSingle("givenName=", value)
   351  				continue
   352  			case pkix.OIDInitials[3]:
   353  				addSingle("initials=", value)
   354  				continue
   355  			case pkix.OIDGenerationQualifier[3]:
   356  				addSingle("generationQualifier=", value)
   357  				continue
   358  			}
   359  		}
   360  		addSingle(t.String()+"=", value)
   361  	}
   362  	return result.String()
   363  }
   364  
   365  // OtherNameToString creates a string description of an x509.OtherName object.
   366  func OtherNameToString(other x509.OtherName) string {
   367  	return fmt.Sprintf("%v=%v", other.TypeID, hex.EncodeToString(other.Value.Bytes))
   368  }
   369  
   370  // GeneralNamesToString creates a string description of an x509.GeneralNames object.
   371  func GeneralNamesToString(gname *x509.GeneralNames) string {
   372  	var buf bytes.Buffer
   373  	for _, name := range gname.DNSNames {
   374  		commaAppend(&buf, "DNS:"+name)
   375  	}
   376  	for _, email := range gname.EmailAddresses {
   377  		commaAppend(&buf, "email:"+email)
   378  	}
   379  	for _, name := range gname.DirectoryNames {
   380  		commaAppend(&buf, "DirName:"+NameToString(name))
   381  	}
   382  	for _, uri := range gname.URIs {
   383  		commaAppend(&buf, "URI:"+uri)
   384  	}
   385  	for _, ip := range gname.IPNets {
   386  		if ip.Mask == nil {
   387  			commaAppend(&buf, "IP Address:"+ip.IP.String())
   388  		} else {
   389  			commaAppend(&buf, "IP Address:"+ip.IP.String()+"/"+ip.Mask.String())
   390  		}
   391  	}
   392  	for _, id := range gname.RegisteredIDs {
   393  		commaAppend(&buf, "Registered ID:"+id.String())
   394  	}
   395  	for _, other := range gname.OtherNames {
   396  		commaAppend(&buf, "othername:"+OtherNameToString(other))
   397  	}
   398  	return buf.String()
   399  }
   400  
   401  // CertificateToString generates a string describing the given certificate.
   402  // The output roughly resembles that from openssl x509 -text.
   403  func CertificateToString(cert *x509.Certificate) string {
   404  	var result bytes.Buffer
   405  	result.WriteString("Certificate:\n")
   406  	result.WriteString("    Data:\n")
   407  	result.WriteString(fmt.Sprintf("        Version: %d (%#x)\n", cert.Version, cert.Version-1))
   408  	result.WriteString(fmt.Sprintf("        Serial Number: %s (0x%s)\n", cert.SerialNumber.Text(10), cert.SerialNumber.Text(16)))
   409  	result.WriteString(fmt.Sprintf("    Signature Algorithm: %v\n", cert.SignatureAlgorithm))
   410  	result.WriteString(fmt.Sprintf("        Issuer: %v\n", NameToString(cert.Issuer)))
   411  	result.WriteString("        Validity:\n")
   412  	result.WriteString(fmt.Sprintf("            Not Before: %v\n", cert.NotBefore))
   413  	result.WriteString(fmt.Sprintf("            Not After : %v\n", cert.NotAfter))
   414  	result.WriteString(fmt.Sprintf("        Subject: %v\n", NameToString(cert.Subject)))
   415  	result.WriteString("        Subject Public Key Info:\n")
   416  	result.WriteString(fmt.Sprintf("            Public Key Algorithm: %v\n", publicKeyAlgorithmToString(cert.PublicKeyAlgorithm)))
   417  	result.WriteString(fmt.Sprintf("%v\n", publicKeyToString(cert.PublicKeyAlgorithm, cert.PublicKey)))
   418  
   419  	if len(cert.Extensions) > 0 {
   420  		result.WriteString("        X509v3 extensions:\n")
   421  	}
   422  	// First display the extensions that are already cracked out
   423  	showAuthKeyID(&result, cert)
   424  	showSubjectKeyID(&result, cert)
   425  	showKeyUsage(&result, cert)
   426  	showExtendedKeyUsage(&result, cert)
   427  	showBasicConstraints(&result, cert)
   428  	showSubjectAltName(&result, cert)
   429  	showNameConstraints(&result, cert)
   430  	showCertPolicies(&result, cert)
   431  	showCRLDPs(&result, cert)
   432  	showAuthInfoAccess(&result, cert)
   433  	showSubjectInfoAccess(&result, cert)
   434  	showRPKIAddressRanges(&result, cert)
   435  	showRPKIASIdentifiers(&result, cert)
   436  	showCTPoison(&result, cert)
   437  	showCTSCT(&result, cert)
   438  	showCTLogSTHInfo(&result, cert)
   439  
   440  	showUnhandledExtensions(&result, cert)
   441  	showSignature(&result, cert)
   442  
   443  	return result.String()
   444  }
   445  
   446  func showCritical(result *bytes.Buffer, critical bool) {
   447  	if critical {
   448  		result.WriteString(" critical")
   449  	}
   450  	result.WriteString("\n")
   451  }
   452  
   453  func showAuthKeyID(result *bytes.Buffer, cert *x509.Certificate) {
   454  	count, critical := OIDInExtensions(x509.OIDExtensionAuthorityKeyId, cert.Extensions)
   455  	if count > 0 {
   456  		result.WriteString("            X509v3 Authority Key Identifier:")
   457  		showCritical(result, critical)
   458  		result.WriteString(fmt.Sprintf("                keyid:%v\n", hex.EncodeToString(cert.AuthorityKeyId)))
   459  	}
   460  }
   461  
   462  func showSubjectKeyID(result *bytes.Buffer, cert *x509.Certificate) {
   463  	count, critical := OIDInExtensions(x509.OIDExtensionSubjectKeyId, cert.Extensions)
   464  	if count > 0 {
   465  		result.WriteString("            X509v3 Subject Key Identifier:")
   466  		showCritical(result, critical)
   467  		result.WriteString(fmt.Sprintf("                keyid:%v\n", hex.EncodeToString(cert.SubjectKeyId)))
   468  	}
   469  }
   470  
   471  func showKeyUsage(result *bytes.Buffer, cert *x509.Certificate) {
   472  	count, critical := OIDInExtensions(x509.OIDExtensionKeyUsage, cert.Extensions)
   473  	if count > 0 {
   474  		result.WriteString("            X509v3 Key Usage:")
   475  		showCritical(result, critical)
   476  		result.WriteString(fmt.Sprintf("                %v\n", keyUsageToString(cert.KeyUsage)))
   477  	}
   478  }
   479  
   480  func showExtendedKeyUsage(result *bytes.Buffer, cert *x509.Certificate) {
   481  	count, critical := OIDInExtensions(x509.OIDExtensionExtendedKeyUsage, cert.Extensions)
   482  	if count > 0 {
   483  		result.WriteString("            X509v3 Extended Key Usage:")
   484  		showCritical(result, critical)
   485  		var usages bytes.Buffer
   486  		for _, usage := range cert.ExtKeyUsage {
   487  			commaAppend(&usages, extKeyUsageToString(usage))
   488  		}
   489  		for _, oid := range cert.UnknownExtKeyUsage {
   490  			commaAppend(&usages, oid.String())
   491  		}
   492  		result.WriteString(fmt.Sprintf("                %v\n", usages.String()))
   493  	}
   494  }
   495  
   496  func showBasicConstraints(result *bytes.Buffer, cert *x509.Certificate) {
   497  	count, critical := OIDInExtensions(x509.OIDExtensionBasicConstraints, cert.Extensions)
   498  	if count > 0 {
   499  		result.WriteString("            X509v3 Basic Constraints:")
   500  		showCritical(result, critical)
   501  		result.WriteString(fmt.Sprintf("                CA:%t", cert.IsCA))
   502  		if cert.MaxPathLen > 0 || cert.MaxPathLenZero {
   503  			result.WriteString(fmt.Sprintf(", pathlen:%d", cert.MaxPathLen))
   504  		}
   505  		result.WriteString("\n")
   506  	}
   507  }
   508  
   509  func showSubjectAltName(result *bytes.Buffer, cert *x509.Certificate) {
   510  	count, critical := OIDInExtensions(x509.OIDExtensionSubjectAltName, cert.Extensions)
   511  	if count > 0 {
   512  		result.WriteString("            X509v3 Subject Alternative Name:")
   513  		showCritical(result, critical)
   514  		var buf bytes.Buffer
   515  		for _, name := range cert.DNSNames {
   516  			commaAppend(&buf, "DNS:"+name)
   517  		}
   518  		for _, email := range cert.EmailAddresses {
   519  			commaAppend(&buf, "email:"+email)
   520  		}
   521  		for _, ip := range cert.IPAddresses {
   522  			commaAppend(&buf, "IP Address:"+ip.String())
   523  		}
   524  
   525  		result.WriteString(fmt.Sprintf("                %v\n", buf.String()))
   526  		// TODO(drysdale): include other name forms
   527  	}
   528  }
   529  
   530  func showNameConstraints(result *bytes.Buffer, cert *x509.Certificate) {
   531  	count, critical := OIDInExtensions(x509.OIDExtensionNameConstraints, cert.Extensions)
   532  	if count > 0 {
   533  		result.WriteString("            X509v3 Name Constraints:")
   534  		showCritical(result, critical)
   535  		if len(cert.PermittedDNSDomains) > 0 {
   536  			result.WriteString("                Permitted:\n")
   537  			var buf bytes.Buffer
   538  			for _, name := range cert.PermittedDNSDomains {
   539  				commaAppend(&buf, "DNS:"+name)
   540  			}
   541  			result.WriteString(fmt.Sprintf("                  %v\n", buf.String()))
   542  		}
   543  		// TODO(drysdale): include other name forms
   544  	}
   545  
   546  }
   547  
   548  func showCertPolicies(result *bytes.Buffer, cert *x509.Certificate) {
   549  	count, critical := OIDInExtensions(x509.OIDExtensionCertificatePolicies, cert.Extensions)
   550  	if count > 0 {
   551  		result.WriteString("            X509v3 Certificate Policies:")
   552  		showCritical(result, critical)
   553  		for _, oid := range cert.PolicyIdentifiers {
   554  			result.WriteString(fmt.Sprintf("                Policy: %v\n", oid.String()))
   555  			// TODO(drysdale): Display any qualifiers associated with the policy
   556  		}
   557  	}
   558  
   559  }
   560  
   561  func showCRLDPs(result *bytes.Buffer, cert *x509.Certificate) {
   562  	count, critical := OIDInExtensions(x509.OIDExtensionCRLDistributionPoints, cert.Extensions)
   563  	if count > 0 {
   564  		result.WriteString("            X509v3 CRL Distribution Points:")
   565  		showCritical(result, critical)
   566  		result.WriteString("                Full Name:\n")
   567  		var buf bytes.Buffer
   568  		for _, pt := range cert.CRLDistributionPoints {
   569  			commaAppend(&buf, "URI:"+pt)
   570  		}
   571  		result.WriteString(fmt.Sprintf("                    %v\n", buf.String()))
   572  		// TODO(drysdale): Display other GeneralNames types, plus issuer/reasons/relative-name
   573  	}
   574  
   575  }
   576  
   577  func showAuthInfoAccess(result *bytes.Buffer, cert *x509.Certificate) {
   578  	count, critical := OIDInExtensions(x509.OIDExtensionAuthorityInfoAccess, cert.Extensions)
   579  	if count > 0 {
   580  		result.WriteString("            Authority Information Access:")
   581  		showCritical(result, critical)
   582  		var issuerBuf bytes.Buffer
   583  		for _, issuer := range cert.IssuingCertificateURL {
   584  			commaAppend(&issuerBuf, "URI:"+issuer)
   585  		}
   586  		if issuerBuf.Len() > 0 {
   587  			result.WriteString(fmt.Sprintf("                CA Issuers - %v\n", issuerBuf.String()))
   588  		}
   589  		var ocspBuf bytes.Buffer
   590  		for _, ocsp := range cert.OCSPServer {
   591  			commaAppend(&ocspBuf, "URI:"+ocsp)
   592  		}
   593  		if ocspBuf.Len() > 0 {
   594  			result.WriteString(fmt.Sprintf("                OCSP - %v\n", ocspBuf.String()))
   595  		}
   596  		// TODO(drysdale): Display other GeneralNames types
   597  	}
   598  }
   599  
   600  func showSubjectInfoAccess(result *bytes.Buffer, cert *x509.Certificate) {
   601  	count, critical := OIDInExtensions(x509.OIDExtensionSubjectInfoAccess, cert.Extensions)
   602  	if count > 0 {
   603  		result.WriteString("            Subject Information Access:")
   604  		showCritical(result, critical)
   605  		var tsBuf bytes.Buffer
   606  		for _, ts := range cert.SubjectTimestamps {
   607  			commaAppend(&tsBuf, "URI:"+ts)
   608  		}
   609  		if tsBuf.Len() > 0 {
   610  			result.WriteString(fmt.Sprintf("                AD Time Stamping - %v\n", tsBuf.String()))
   611  		}
   612  		var repoBuf bytes.Buffer
   613  		for _, repo := range cert.SubjectCARepositories {
   614  			commaAppend(&repoBuf, "URI:"+repo)
   615  		}
   616  		if repoBuf.Len() > 0 {
   617  			result.WriteString(fmt.Sprintf("                CA repository - %v\n", repoBuf.String()))
   618  		}
   619  	}
   620  }
   621  
   622  func showAddressRange(prefix x509.IPAddressPrefix, afi uint16) string {
   623  	switch afi {
   624  	case x509.IPv4AddressFamilyIndicator, x509.IPv6AddressFamilyIndicator:
   625  		size := 4
   626  		if afi == x509.IPv6AddressFamilyIndicator {
   627  			size = 16
   628  		}
   629  		ip := make([]byte, size)
   630  		copy(ip, prefix.Bytes)
   631  		addr := net.IPNet{IP: ip, Mask: net.CIDRMask(prefix.BitLength, 8*size)}
   632  		return addr.String()
   633  	default:
   634  		return fmt.Sprintf("%x/%d", prefix.Bytes, prefix.BitLength)
   635  	}
   636  
   637  }
   638  
   639  func showRPKIAddressRanges(result *bytes.Buffer, cert *x509.Certificate) {
   640  	count, critical := OIDInExtensions(x509.OIDExtensionIPPrefixList, cert.Extensions)
   641  	if count > 0 {
   642  		result.WriteString("            sbgp-ipAddrBlock:")
   643  		showCritical(result, critical)
   644  		for _, blocks := range cert.RPKIAddressRanges {
   645  			afi := blocks.AFI
   646  			switch afi {
   647  			case x509.IPv4AddressFamilyIndicator:
   648  				result.WriteString("                IPv4")
   649  			case x509.IPv6AddressFamilyIndicator:
   650  				result.WriteString("                IPv6")
   651  			default:
   652  				result.WriteString(fmt.Sprintf("                %d", afi))
   653  			}
   654  			if blocks.SAFI != 0 {
   655  				result.WriteString(fmt.Sprintf(" SAFI=%d", blocks.SAFI))
   656  			}
   657  			result.WriteString(":")
   658  			if blocks.InheritFromIssuer {
   659  				result.WriteString(" inherit\n")
   660  				continue
   661  			}
   662  			result.WriteString("\n")
   663  			for _, prefix := range blocks.AddressPrefixes {
   664  				result.WriteString(fmt.Sprintf("                  %s\n", showAddressRange(prefix, afi)))
   665  			}
   666  			for _, ipRange := range blocks.AddressRanges {
   667  				result.WriteString(fmt.Sprintf("                  [%s, %s]\n", showAddressRange(ipRange.Min, afi), showAddressRange(ipRange.Max, afi)))
   668  			}
   669  		}
   670  	}
   671  }
   672  
   673  func showASIDs(result *bytes.Buffer, asids *x509.ASIdentifiers, label string) {
   674  	if asids == nil {
   675  		return
   676  	}
   677  	result.WriteString(fmt.Sprintf("                %s:\n", label))
   678  	if asids.InheritFromIssuer {
   679  		result.WriteString("                  inherit\n")
   680  		return
   681  	}
   682  	for _, id := range asids.ASIDs {
   683  		result.WriteString(fmt.Sprintf("                  %d\n", id))
   684  	}
   685  	for _, idRange := range asids.ASIDRanges {
   686  		result.WriteString(fmt.Sprintf("                  %d-%d\n", idRange.Min, idRange.Max))
   687  	}
   688  }
   689  
   690  func showRPKIASIdentifiers(result *bytes.Buffer, cert *x509.Certificate) {
   691  	count, critical := OIDInExtensions(x509.OIDExtensionASList, cert.Extensions)
   692  	if count > 0 {
   693  		result.WriteString("            sbgp-autonomousSysNum:")
   694  		showCritical(result, critical)
   695  		showASIDs(result, cert.RPKIASNumbers, "Autonomous System Numbers")
   696  		showASIDs(result, cert.RPKIRoutingDomainIDs, "Routing Domain Identifiers")
   697  	}
   698  }
   699  func showCTPoison(result *bytes.Buffer, cert *x509.Certificate) {
   700  	count, critical := OIDInExtensions(x509.OIDExtensionCTPoison, cert.Extensions)
   701  	if count > 0 {
   702  		result.WriteString("            RFC6962 Pre-Certificate Poison:")
   703  		showCritical(result, critical)
   704  		result.WriteString("                .....\n")
   705  	}
   706  }
   707  
   708  func showCTSCT(result *bytes.Buffer, cert *x509.Certificate) {
   709  	count, critical := OIDInExtensions(x509.OIDExtensionCTSCT, cert.Extensions)
   710  	if count > 0 {
   711  		result.WriteString("            RFC6962 Certificate Transparency SCT:")
   712  		showCritical(result, critical)
   713  		for i, sctData := range cert.SCTList.SCTList {
   714  			result.WriteString(fmt.Sprintf("              SCT [%d]:\n", i))
   715  			var sct ct.SignedCertificateTimestamp
   716  			_, err := tls.Unmarshal(sctData.Val, &sct)
   717  			if err != nil {
   718  				appendHexData(result, sctData.Val, 16, "                  ")
   719  				result.WriteString("\n")
   720  				continue
   721  			}
   722  			result.WriteString(fmt.Sprintf("                  Version: %d\n", sct.SCTVersion))
   723  			result.WriteString(fmt.Sprintf("                  LogID: %s\n", base64.StdEncoding.EncodeToString(sct.LogID.KeyID[:])))
   724  			result.WriteString(fmt.Sprintf("                  Timestamp: %d\n", sct.Timestamp))
   725  			result.WriteString(fmt.Sprintf("                  Signature: %s\n", sct.Signature.Algorithm))
   726  			result.WriteString("                  Signature:\n")
   727  			appendHexData(result, sct.Signature.Signature, 16, "                    ")
   728  			result.WriteString("\n")
   729  		}
   730  	}
   731  }
   732  
   733  func showCTLogSTHInfo(result *bytes.Buffer, cert *x509.Certificate) {
   734  	count, critical := OIDInExtensions(x509ext.OIDExtensionCTSTH, cert.Extensions)
   735  	if count > 0 {
   736  		result.WriteString("            Certificate Transparency STH:")
   737  		showCritical(result, critical)
   738  		sthInfo, err := x509ext.LogSTHInfoFromCert(cert)
   739  		if err != nil {
   740  			result.WriteString("              Failed to decode STH:\n")
   741  			return
   742  		}
   743  		result.WriteString(fmt.Sprintf("              LogURL: %s\n", string(sthInfo.LogURL)))
   744  		result.WriteString(fmt.Sprintf("              Version: %d\n", sthInfo.Version))
   745  		result.WriteString(fmt.Sprintf("              TreeSize: %d\n", sthInfo.TreeSize))
   746  		result.WriteString(fmt.Sprintf("              Timestamp: %d\n", sthInfo.Timestamp))
   747  		result.WriteString("              RootHash:\n")
   748  		appendHexData(result, sthInfo.SHA256RootHash[:], 16, "                    ")
   749  		result.WriteString("\n")
   750  		result.WriteString(fmt.Sprintf("              TreeHeadSignature: %s\n", sthInfo.TreeHeadSignature.Algorithm))
   751  		appendHexData(result, sthInfo.TreeHeadSignature.Signature, 16, "                    ")
   752  		result.WriteString("\n")
   753  	}
   754  }
   755  
   756  func showUnhandledExtensions(result *bytes.Buffer, cert *x509.Certificate) {
   757  	for _, ext := range cert.Extensions {
   758  		// Skip extensions that are already cracked out
   759  		if oidAlreadyPrinted(ext.Id) {
   760  			continue
   761  		}
   762  		result.WriteString(fmt.Sprintf("            %v:", ext.Id))
   763  		showCritical(result, ext.Critical)
   764  		appendHexData(result, ext.Value, 16, "                ")
   765  		result.WriteString("\n")
   766  	}
   767  }
   768  
   769  func showSignature(result *bytes.Buffer, cert *x509.Certificate) {
   770  	result.WriteString(fmt.Sprintf("    Signature Algorithm: %v\n", cert.SignatureAlgorithm))
   771  	appendHexData(result, cert.Signature, 18, "         ")
   772  	result.WriteString("\n")
   773  }
   774  
   775  // TODO(drysdale): remove this once all standard OIDs are parsed and printed.
   776  func oidAlreadyPrinted(oid asn1.ObjectIdentifier) bool {
   777  	if oid.Equal(x509.OIDExtensionSubjectKeyId) ||
   778  		oid.Equal(x509.OIDExtensionKeyUsage) ||
   779  		oid.Equal(x509.OIDExtensionExtendedKeyUsage) ||
   780  		oid.Equal(x509.OIDExtensionAuthorityKeyId) ||
   781  		oid.Equal(x509.OIDExtensionBasicConstraints) ||
   782  		oid.Equal(x509.OIDExtensionSubjectAltName) ||
   783  		oid.Equal(x509.OIDExtensionCertificatePolicies) ||
   784  		oid.Equal(x509.OIDExtensionNameConstraints) ||
   785  		oid.Equal(x509.OIDExtensionCRLDistributionPoints) ||
   786  		oid.Equal(x509.OIDExtensionAuthorityInfoAccess) ||
   787  		oid.Equal(x509.OIDExtensionSubjectInfoAccess) ||
   788  		oid.Equal(x509.OIDExtensionIPPrefixList) ||
   789  		oid.Equal(x509.OIDExtensionASList) ||
   790  		oid.Equal(x509.OIDExtensionCTPoison) ||
   791  		oid.Equal(x509.OIDExtensionCTSCT) ||
   792  		oid.Equal(x509ext.OIDExtensionCTSTH) {
   793  		return true
   794  	}
   795  	return false
   796  }
   797  
   798  // CertificateFromPEM takes a certificate in PEM format and returns the
   799  // corresponding x509.Certificate object.
   800  func CertificateFromPEM(pemBytes []byte) (*x509.Certificate, error) {
   801  	block, rest := pem.Decode(pemBytes)
   802  	if len(rest) != 0 {
   803  		return nil, errors.New("trailing data found after PEM block")
   804  	}
   805  	if block == nil {
   806  		return nil, errors.New("PEM block is nil")
   807  	}
   808  	if block.Type != "CERTIFICATE" {
   809  		return nil, errors.New("PEM block is not a CERTIFICATE")
   810  	}
   811  	return x509.ParseCertificate(block.Bytes)
   812  }
   813  
   814  // CertificatesFromPEM parses one or more certificates from the given PEM data.
   815  // The PEM certificates must be concatenated.  This function can be used for
   816  // parsing PEM-formatted certificate chains, but does not verify that the
   817  // resulting chain is a valid certificate chain.
   818  func CertificatesFromPEM(pemBytes []byte) ([]*x509.Certificate, error) {
   819  	var chain []*x509.Certificate
   820  	for {
   821  		var block *pem.Block
   822  		block, pemBytes = pem.Decode(pemBytes)
   823  		if block == nil {
   824  			return chain, nil
   825  		}
   826  		if block.Type != "CERTIFICATE" {
   827  			return nil, fmt.Errorf("PEM block is not a CERTIFICATE")
   828  		}
   829  		cert, err := x509.ParseCertificate(block.Bytes)
   830  		if err != nil {
   831  			return nil, errors.New("failed to parse certificate")
   832  		}
   833  		chain = append(chain, cert)
   834  	}
   835  }
   836  
   837  // ParseSCTsFromSCTList parses each of the SCTs contained within an SCT list.
   838  func ParseSCTsFromSCTList(sctList *x509.SignedCertificateTimestampList) ([]*ct.SignedCertificateTimestamp, error) {
   839  	var scts []*ct.SignedCertificateTimestamp
   840  	for i, data := range sctList.SCTList {
   841  		sct, err := ExtractSCT(&data)
   842  		if err != nil {
   843  			return nil, fmt.Errorf("error extracting SCT number %d: %s", i, err)
   844  		}
   845  		scts = append(scts, sct)
   846  	}
   847  	return scts, nil
   848  }
   849  
   850  // ExtractSCT deserializes an SCT from a TLS-encoded SCT.
   851  func ExtractSCT(sctData *x509.SerializedSCT) (*ct.SignedCertificateTimestamp, error) {
   852  	if sctData == nil {
   853  		return nil, errors.New("SCT is nil")
   854  	}
   855  	var sct ct.SignedCertificateTimestamp
   856  	if rest, err := tls.Unmarshal(sctData.Val, &sct); err != nil {
   857  		return nil, fmt.Errorf("error parsing SCT: %s", err)
   858  	} else if len(rest) > 0 {
   859  		return nil, fmt.Errorf("extra data (%d bytes) after serialized SCT", len(rest))
   860  	}
   861  	return &sct, nil
   862  }
   863  
   864  // MarshalSCTsIntoSCTList serializes SCTs into SCT list.
   865  func MarshalSCTsIntoSCTList(scts []*ct.SignedCertificateTimestamp) (*x509.SignedCertificateTimestampList, error) {
   866  	var sctList x509.SignedCertificateTimestampList
   867  	sctList.SCTList = []x509.SerializedSCT{}
   868  	for i, sct := range scts {
   869  		if sct == nil {
   870  			return nil, fmt.Errorf("SCT number %d is nil", i)
   871  		}
   872  		encd, err := tls.Marshal(*sct)
   873  		if err != nil {
   874  			return nil, fmt.Errorf("error serializing SCT number %d: %s", i, err)
   875  		}
   876  		sctData := x509.SerializedSCT{Val: encd}
   877  		sctList.SCTList = append(sctList.SCTList, sctData)
   878  	}
   879  	return &sctList, nil
   880  }
   881  
   882  var pemCertificatePrefix = []byte("-----BEGIN CERTIFICATE")
   883  
   884  // ParseSCTsFromCertificate parses any SCTs that are embedded in the
   885  // certificate provided.  The certificate bytes provided can be either DER or
   886  // PEM, provided the PEM data starts with the PEM block marker (i.e. has no
   887  // leading text).
   888  func ParseSCTsFromCertificate(certBytes []byte) ([]*ct.SignedCertificateTimestamp, error) {
   889  	var cert *x509.Certificate
   890  	var err error
   891  	if bytes.HasPrefix(certBytes, pemCertificatePrefix) {
   892  		cert, err = CertificateFromPEM(certBytes)
   893  	} else {
   894  		cert, err = x509.ParseCertificate(certBytes)
   895  	}
   896  	if err != nil {
   897  		return nil, fmt.Errorf("failed to parse certificate: %s", err)
   898  	}
   899  	return ParseSCTsFromSCTList(&cert.SCTList)
   900  }
   901  

View as plain text