1// Copyright (c) 2020, Google Inc. 2// 3// Permission to use, copy, modify, and/or distribute this software for any 4// purpose with or without fee is hereby granted, provided that the above 5// copyright notice and this permission notice appear in all copies. 6// 7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 15//go:build ignore 16 17// make_invalid_extensions.go generates a number of certificate chains with 18// invalid extension encodings. 19package main 20 21import ( 22 "crypto/ecdsa" 23 "crypto/rand" 24 "crypto/x509" 25 "crypto/x509/pkix" 26 "encoding/pem" 27 "fmt" 28 "math/big" 29 "os" 30 "time" 31) 32 33type extension struct { 34 // The name of the extension, in a form suitable for including in a 35 // filename. 36 name string 37 // The extension's OID. 38 oid []int 39} 40 41var extensions = []extension{ 42 {name: "authority_key_identifier", oid: []int{2, 5, 29, 35}}, 43 {name: "basic_constraints", oid: []int{2, 5, 29, 19}}, 44 {name: "ext_key_usage", oid: []int{2, 5, 29, 37}}, 45 {name: "key_usage", oid: []int{2, 5, 29, 15}}, 46 {name: "name_constraints", oid: []int{2, 5, 29, 30}}, 47 {name: "subject_alt_name", oid: []int{2, 5, 29, 17}}, 48 {name: "subject_key_identifier", oid: []int{2, 5, 29, 14}}, 49} 50 51var leafKey, intermediateKey, rootKey *ecdsa.PrivateKey 52 53func init() { 54 leafKey = mustParseECDSAKey(leafKeyPEM) 55 intermediateKey = mustParseECDSAKey(intermediateKeyPEM) 56 rootKey = mustParseECDSAKey(rootKeyPEM) 57} 58 59type templateAndKey struct { 60 template x509.Certificate 61 key *ecdsa.PrivateKey 62} 63 64func mustGenerateCertificate(path string, subject, issuer *templateAndKey) []byte { 65 cert, err := x509.CreateCertificate(rand.Reader, &subject.template, &issuer.template, &subject.key.PublicKey, issuer.key) 66 if err != nil { 67 panic(err) 68 } 69 file, err := os.Create(path) 70 if err != nil { 71 panic(err) 72 } 73 defer file.Close() 74 err = pem.Encode(file, &pem.Block{Type: "CERTIFICATE", Bytes: cert}) 75 if err != nil { 76 panic(err) 77 } 78 return cert 79} 80 81func main() { 82 notBefore, err := time.Parse(time.RFC3339, "2000-01-01T00:00:00Z") 83 if err != nil { 84 panic(err) 85 } 86 notAfter, err := time.Parse(time.RFC3339, "2100-01-01T00:00:00Z") 87 if err != nil { 88 panic(err) 89 } 90 91 root := templateAndKey{ 92 template: x509.Certificate{ 93 SerialNumber: new(big.Int).SetInt64(1), 94 Subject: pkix.Name{CommonName: "Invalid Extensions Root"}, 95 NotBefore: notBefore, 96 NotAfter: notAfter, 97 BasicConstraintsValid: true, 98 IsCA: true, 99 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 100 KeyUsage: x509.KeyUsageCertSign, 101 SignatureAlgorithm: x509.ECDSAWithSHA256, 102 SubjectKeyId: []byte("root"), 103 }, 104 key: rootKey, 105 } 106 intermediate := templateAndKey{ 107 template: x509.Certificate{ 108 SerialNumber: new(big.Int).SetInt64(2), 109 Subject: pkix.Name{CommonName: "Invalid Extensions Intermediate"}, 110 NotBefore: notBefore, 111 NotAfter: notAfter, 112 BasicConstraintsValid: true, 113 IsCA: true, 114 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 115 KeyUsage: x509.KeyUsageCertSign, 116 SignatureAlgorithm: x509.ECDSAWithSHA256, 117 SubjectKeyId: []byte("intermediate"), 118 }, 119 key: intermediateKey, 120 } 121 leaf := templateAndKey{ 122 template: x509.Certificate{ 123 SerialNumber: new(big.Int).SetInt64(3), 124 Subject: pkix.Name{CommonName: "www.example.com"}, 125 NotBefore: notBefore, 126 NotAfter: notAfter, 127 BasicConstraintsValid: true, 128 IsCA: false, 129 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 130 KeyUsage: x509.KeyUsageCertSign, 131 SignatureAlgorithm: x509.ECDSAWithSHA256, 132 DNSNames: []string{"www.example.com"}, 133 SubjectKeyId: []byte("leaf"), 134 PermittedDNSDomains: []string{"www.example.com"}, 135 }, 136 key: leafKey, 137 } 138 139 // Generate a valid certificate chain from the templates. 140 mustGenerateCertificate("invalid_extension_root.pem", &root, &root) 141 mustGenerateCertificate("invalid_extension_intermediate.pem", &intermediate, &root) 142 leafDER := mustGenerateCertificate("invalid_extension_leaf.pem", &leaf, &intermediate) 143 144 leafCert, err := x509.ParseCertificate(leafDER) 145 if err != nil { 146 panic(err) 147 } 148 149 // Make copies of the certificates with invalid extensions. These copies may 150 // be substituted into the valid chain. 151 for _, ext := range extensions { 152 invalidExtension := []pkix.Extension{{Id: ext.oid, Value: []byte("INVALID")}} 153 154 rootInvalid := root 155 rootInvalid.template.ExtraExtensions = invalidExtension 156 mustGenerateCertificate(fmt.Sprintf("invalid_extension_root_%s.pem", ext.name), &rootInvalid, &rootInvalid) 157 158 intermediateInvalid := intermediate 159 intermediateInvalid.template.ExtraExtensions = invalidExtension 160 mustGenerateCertificate(fmt.Sprintf("invalid_extension_intermediate_%s.pem", ext.name), &intermediateInvalid, &root) 161 162 leafInvalid := leaf 163 leafInvalid.template.ExtraExtensions = invalidExtension 164 mustGenerateCertificate(fmt.Sprintf("invalid_extension_leaf_%s.pem", ext.name), &leafInvalid, &intermediate) 165 166 // Additionally generate a copy of the leaf certificate with extra data in 167 // the extension. 168 var trailingDataExtension []pkix.Extension 169 for _, leafExt := range leafCert.Extensions { 170 if leafExt.Id.Equal(ext.oid) { 171 newValue := make([]byte, len(leafExt.Value)+1) 172 copy(newValue, leafExt.Value) 173 trailingDataExtension = append(trailingDataExtension, pkix.Extension{Id: ext.oid, Critical: leafExt.Critical, Value: newValue}) 174 } 175 } 176 if len(trailingDataExtension) != 1 { 177 panic(fmt.Sprintf("could not find sample extension %s", ext.name)) 178 } 179 180 leafTrailingData := leaf 181 leafTrailingData.template.ExtraExtensions = trailingDataExtension 182 mustGenerateCertificate(fmt.Sprintf("trailing_data_leaf_%s.pem", ext.name), &leafTrailingData, &intermediate) 183 } 184} 185 186const leafKeyPEM = `-----BEGIN PRIVATE KEY----- 187MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoPUXNXuH9mgiS/nk 188024SYxryxMa3CyGJldiHymLxSquhRANCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5 189w8u3SSwm7HZREvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5X 190-----END PRIVATE KEY-----` 191 192const intermediateKeyPEM = `-----BEGIN PRIVATE KEY----- 193MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWHKCKgY058ahE3t6 194vpxVQgzlycgCVMogwjK0y3XMNfWhRANCAATiOnyojN4xS5C8gJ/PHL5cOEsMbsoE 195Y6KT9xRQSh8lEL4d1Vb36kqUgkpqedEImo0Og4Owk6VWVVR/m4Lk+yUw 196-----END PRIVATE KEY-----` 197 198const rootKeyPEM = `-----BEGIN PRIVATE KEY----- 199MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgBwND/eHytW0I417J 200Hr+qcPlp5N1jM3ACXys57bPujg+hRANCAAQmdqXYl1GvY7y3jcTTK6MVXIQr44Tq 201ChRYI6IeV9tIB6jIsOY+Qol1bk8x/7A5FGOnUWFVLEAPEPSJwPndjolt 202-----END PRIVATE KEY-----` 203 204func mustParseECDSAKey(in string) *ecdsa.PrivateKey { 205 keyBlock, _ := pem.Decode([]byte(in)) 206 if keyBlock == nil || keyBlock.Type != "PRIVATE KEY" { 207 panic("could not decode private key") 208 } 209 key, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes) 210 if err != nil { 211 panic(err) 212 } 213 return key.(*ecdsa.PrivateKey) 214} 215