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