...

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

Documentation: github.com/google/certificate-transparency-go/x509/pkix

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package pkix contains shared, low level structures used for ASN.1 parsing
     6  // and serialization of X.509 certificates, CRL and OCSP.
     7  package pkix
     8  
     9  import (
    10  	"encoding/hex"
    11  	"fmt"
    12  	"math/big"
    13  	"time"
    14  
    15  	"github.com/google/certificate-transparency-go/asn1"
    16  )
    17  
    18  // AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
    19  // 5280, section 4.1.1.2.
    20  type AlgorithmIdentifier struct {
    21  	Algorithm  asn1.ObjectIdentifier
    22  	Parameters asn1.RawValue `asn1:"optional"`
    23  }
    24  
    25  type RDNSequence []RelativeDistinguishedNameSET
    26  
    27  var attributeTypeNames = map[string]string{
    28  	"2.5.4.6":  "C",
    29  	"2.5.4.10": "O",
    30  	"2.5.4.11": "OU",
    31  	"2.5.4.3":  "CN",
    32  	"2.5.4.5":  "SERIALNUMBER",
    33  	"2.5.4.7":  "L",
    34  	"2.5.4.8":  "ST",
    35  	"2.5.4.9":  "STREET",
    36  	"2.5.4.17": "POSTALCODE",
    37  }
    38  
    39  // String returns a string representation of the sequence r,
    40  // roughly following the RFC 2253 Distinguished Names syntax.
    41  func (r RDNSequence) String() string {
    42  	s := ""
    43  	for i := 0; i < len(r); i++ {
    44  		rdn := r[len(r)-1-i]
    45  		if i > 0 {
    46  			s += ","
    47  		}
    48  		for j, tv := range rdn {
    49  			if j > 0 {
    50  				s += "+"
    51  			}
    52  
    53  			oidString := tv.Type.String()
    54  			typeName, ok := attributeTypeNames[oidString]
    55  			if !ok {
    56  				derBytes, err := asn1.Marshal(tv.Value)
    57  				if err == nil {
    58  					s += oidString + "=#" + hex.EncodeToString(derBytes)
    59  					continue // No value escaping necessary.
    60  				}
    61  
    62  				typeName = oidString
    63  			}
    64  
    65  			valueString := fmt.Sprint(tv.Value)
    66  			escaped := make([]rune, 0, len(valueString))
    67  
    68  			for k, c := range valueString {
    69  				escape := false
    70  
    71  				switch c {
    72  				case ',', '+', '"', '\\', '<', '>', ';':
    73  					escape = true
    74  
    75  				case ' ':
    76  					escape = k == 0 || k == len(valueString)-1
    77  
    78  				case '#':
    79  					escape = k == 0
    80  				}
    81  
    82  				if escape {
    83  					escaped = append(escaped, '\\', c)
    84  				} else {
    85  					escaped = append(escaped, c)
    86  				}
    87  			}
    88  
    89  			s += typeName + "=" + string(escaped)
    90  		}
    91  	}
    92  
    93  	return s
    94  }
    95  
    96  type RelativeDistinguishedNameSET []AttributeTypeAndValue
    97  
    98  // AttributeTypeAndValue mirrors the ASN.1 structure of the same name in
    99  // RFC 5280, Section 4.1.2.4.
   100  type AttributeTypeAndValue struct {
   101  	Type  asn1.ObjectIdentifier
   102  	Value interface{}
   103  }
   104  
   105  // AttributeTypeAndValueSET represents a set of ASN.1 sequences of
   106  // AttributeTypeAndValue sequences from RFC 2986 (PKCS #10).
   107  type AttributeTypeAndValueSET struct {
   108  	Type  asn1.ObjectIdentifier
   109  	Value [][]AttributeTypeAndValue `asn1:"set"`
   110  }
   111  
   112  // Extension represents the ASN.1 structure of the same name. See RFC
   113  // 5280, section 4.2.
   114  type Extension struct {
   115  	Id       asn1.ObjectIdentifier
   116  	Critical bool `asn1:"optional"`
   117  	Value    []byte
   118  }
   119  
   120  // Name represents an X.509 distinguished name. This only includes the common
   121  // elements of a DN. When parsing, all elements are stored in Names and
   122  // non-standard elements can be extracted from there. When marshaling, elements
   123  // in ExtraNames are appended and override other values with the same OID.
   124  type Name struct {
   125  	Country, Organization, OrganizationalUnit []string
   126  	Locality, Province                        []string
   127  	StreetAddress, PostalCode                 []string
   128  	SerialNumber, CommonName                  string
   129  
   130  	Names      []AttributeTypeAndValue
   131  	ExtraNames []AttributeTypeAndValue
   132  }
   133  
   134  func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
   135  	for _, rdn := range *rdns {
   136  		if len(rdn) == 0 {
   137  			continue
   138  		}
   139  
   140  		for _, atv := range rdn {
   141  			n.Names = append(n.Names, atv)
   142  			value, ok := atv.Value.(string)
   143  			if !ok {
   144  				continue
   145  			}
   146  
   147  			t := atv.Type
   148  			if len(t) == 4 && t[0] == OIDAttribute[0] && t[1] == OIDAttribute[1] && t[2] == OIDAttribute[2] {
   149  				switch t[3] {
   150  				case OIDCommonName[3]:
   151  					n.CommonName = value
   152  				case OIDSerialNumber[3]:
   153  					n.SerialNumber = value
   154  				case OIDCountry[3]:
   155  					n.Country = append(n.Country, value)
   156  				case OIDLocality[3]:
   157  					n.Locality = append(n.Locality, value)
   158  				case OIDProvince[3]:
   159  					n.Province = append(n.Province, value)
   160  				case OIDStreetAddress[3]:
   161  					n.StreetAddress = append(n.StreetAddress, value)
   162  				case OIDOrganization[3]:
   163  					n.Organization = append(n.Organization, value)
   164  				case OIDOrganizationalUnit[3]:
   165  					n.OrganizationalUnit = append(n.OrganizationalUnit, value)
   166  				case OIDPostalCode[3]:
   167  					n.PostalCode = append(n.PostalCode, value)
   168  				}
   169  			}
   170  		}
   171  	}
   172  }
   173  
   174  var (
   175  	OIDAttribute          = asn1.ObjectIdentifier{2, 5, 4}
   176  	OIDCountry            = asn1.ObjectIdentifier{2, 5, 4, 6}
   177  	OIDOrganization       = asn1.ObjectIdentifier{2, 5, 4, 10}
   178  	OIDOrganizationalUnit = asn1.ObjectIdentifier{2, 5, 4, 11}
   179  	OIDCommonName         = asn1.ObjectIdentifier{2, 5, 4, 3}
   180  	OIDSerialNumber       = asn1.ObjectIdentifier{2, 5, 4, 5}
   181  	OIDLocality           = asn1.ObjectIdentifier{2, 5, 4, 7}
   182  	OIDProvince           = asn1.ObjectIdentifier{2, 5, 4, 8}
   183  	OIDStreetAddress      = asn1.ObjectIdentifier{2, 5, 4, 9}
   184  	OIDPostalCode         = asn1.ObjectIdentifier{2, 5, 4, 17}
   185  
   186  	OIDPseudonym           = asn1.ObjectIdentifier{2, 5, 4, 65}
   187  	OIDTitle               = asn1.ObjectIdentifier{2, 5, 4, 12}
   188  	OIDDnQualifier         = asn1.ObjectIdentifier{2, 5, 4, 46}
   189  	OIDName                = asn1.ObjectIdentifier{2, 5, 4, 41}
   190  	OIDSurname             = asn1.ObjectIdentifier{2, 5, 4, 4}
   191  	OIDGivenName           = asn1.ObjectIdentifier{2, 5, 4, 42}
   192  	OIDInitials            = asn1.ObjectIdentifier{2, 5, 4, 43}
   193  	OIDGenerationQualifier = asn1.ObjectIdentifier{2, 5, 4, 44}
   194  )
   195  
   196  // appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
   197  // and returns the new value. The relativeDistinguishedNameSET contains an
   198  // attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
   199  // search for AttributeTypeAndValue.
   200  func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
   201  	if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
   202  		return in
   203  	}
   204  
   205  	s := make([]AttributeTypeAndValue, len(values))
   206  	for i, value := range values {
   207  		s[i].Type = oid
   208  		s[i].Value = value
   209  	}
   210  
   211  	return append(in, s)
   212  }
   213  
   214  func (n Name) ToRDNSequence() (ret RDNSequence) {
   215  	ret = n.appendRDNs(ret, n.Country, OIDCountry)
   216  	ret = n.appendRDNs(ret, n.Province, OIDProvince)
   217  	ret = n.appendRDNs(ret, n.Locality, OIDLocality)
   218  	ret = n.appendRDNs(ret, n.StreetAddress, OIDStreetAddress)
   219  	ret = n.appendRDNs(ret, n.PostalCode, OIDPostalCode)
   220  	ret = n.appendRDNs(ret, n.Organization, OIDOrganization)
   221  	ret = n.appendRDNs(ret, n.OrganizationalUnit, OIDOrganizationalUnit)
   222  	if len(n.CommonName) > 0 {
   223  		ret = n.appendRDNs(ret, []string{n.CommonName}, OIDCommonName)
   224  	}
   225  	if len(n.SerialNumber) > 0 {
   226  		ret = n.appendRDNs(ret, []string{n.SerialNumber}, OIDSerialNumber)
   227  	}
   228  	for _, atv := range n.ExtraNames {
   229  		ret = append(ret, []AttributeTypeAndValue{atv})
   230  	}
   231  
   232  	return ret
   233  }
   234  
   235  // String returns the string form of n, roughly following
   236  // the RFC 2253 Distinguished Names syntax.
   237  func (n Name) String() string {
   238  	return n.ToRDNSequence().String()
   239  }
   240  
   241  // oidInAttributeTypeAndValue reports whether a type with the given OID exists
   242  // in atv.
   243  func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
   244  	for _, a := range atv {
   245  		if a.Type.Equal(oid) {
   246  			return true
   247  		}
   248  	}
   249  	return false
   250  }
   251  
   252  // CertificateList represents the ASN.1 structure of the same name. See RFC
   253  // 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
   254  // signature.
   255  type CertificateList struct {
   256  	TBSCertList        TBSCertificateList
   257  	SignatureAlgorithm AlgorithmIdentifier
   258  	SignatureValue     asn1.BitString
   259  }
   260  
   261  // HasExpired reports whether certList should have been updated by now.
   262  func (certList *CertificateList) HasExpired(now time.Time) bool {
   263  	return !now.Before(certList.TBSCertList.NextUpdate)
   264  }
   265  
   266  // TBSCertificateList represents the ASN.1 structure TBSCertList. See RFC
   267  // 5280, section 5.1.
   268  type TBSCertificateList struct {
   269  	Raw                 asn1.RawContent
   270  	Version             int `asn1:"optional,default:0"`
   271  	Signature           AlgorithmIdentifier
   272  	Issuer              RDNSequence
   273  	ThisUpdate          time.Time
   274  	NextUpdate          time.Time            `asn1:"optional"`
   275  	RevokedCertificates []RevokedCertificate `asn1:"optional"`
   276  	Extensions          []Extension          `asn1:"tag:0,optional,explicit"`
   277  }
   278  
   279  // RevokedCertificate represents the unnamed ASN.1 structure that makes up the
   280  // revokedCertificates member of the TBSCertList structure. See RFC
   281  // 5280, section 5.1.
   282  type RevokedCertificate struct {
   283  	SerialNumber   *big.Int
   284  	RevocationTime time.Time
   285  	Extensions     []Extension `asn1:"optional"`
   286  }
   287  

View as plain text