...

Source file src/pkg/crypto/x509/pkix/pkix.go

     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	// RFC 5280, 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 reports 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	

View as plain text