blob: 8287bf8d310f10861a37b10c62e141e33c0a3fe3 [file] [log] [blame]
David Benjamin54b04fd2023-01-29 11:56:25 -05001// 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
David Benjaminece1f862023-04-24 16:14:08 -040015//go:build ignore
16
David Benjaminfd86eaa2020-06-17 15:13:16 -040017// 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() {
David Benjamind1b20a92022-12-13 17:10:09 -050054 leafKey = mustParseECDSAKey(leafKeyPEM)
55 intermediateKey = mustParseECDSAKey(intermediateKeyPEM)
56 rootKey = mustParseECDSAKey(rootKeyPEM)
David Benjaminfd86eaa2020-06-17 15:13:16 -040057}
58
59type templateAndKey struct {
60 template x509.Certificate
61 key *ecdsa.PrivateKey
62}
63
David Benjamind1b20a92022-12-13 17:10:09 -050064func mustGenerateCertificate(path string, subject, issuer *templateAndKey) []byte {
David Benjaminfd86eaa2020-06-17 15:13:16 -040065 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 }
David Benjamin491af102021-10-29 09:05:29 -040078 return cert
David Benjaminfd86eaa2020-06-17 15:13:16 -040079}
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,
David Benjamin491af102021-10-29 09:05:29 -0400102 SubjectKeyId: []byte("root"),
David Benjaminfd86eaa2020-06-17 15:13:16 -0400103 },
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,
David Benjamin491af102021-10-29 09:05:29 -0400117 SubjectKeyId: []byte("intermediate"),
David Benjaminfd86eaa2020-06-17 15:13:16 -0400118 },
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"},
David Benjamin491af102021-10-29 09:05:29 -0400133 SubjectKeyId: []byte("leaf"),
134 PermittedDNSDomains: []string{"www.example.com"},
David Benjaminfd86eaa2020-06-17 15:13:16 -0400135 },
136 key: leafKey,
137 }
138
139 // Generate a valid certificate chain from the templates.
David Benjamind1b20a92022-12-13 17:10:09 -0500140 mustGenerateCertificate("invalid_extension_root.pem", &root, &root)
141 mustGenerateCertificate("invalid_extension_intermediate.pem", &intermediate, &root)
142 leafDER := mustGenerateCertificate("invalid_extension_leaf.pem", &leaf, &intermediate)
David Benjaminfd86eaa2020-06-17 15:13:16 -0400143
David Benjamin491af102021-10-29 09:05:29 -0400144 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.
David Benjaminfd86eaa2020-06-17 15:13:16 -0400151 for _, ext := range extensions {
152 invalidExtension := []pkix.Extension{{Id: ext.oid, Value: []byte("INVALID")}}
153
154 rootInvalid := root
155 rootInvalid.template.ExtraExtensions = invalidExtension
David Benjamind1b20a92022-12-13 17:10:09 -0500156 mustGenerateCertificate(fmt.Sprintf("invalid_extension_root_%s.pem", ext.name), &rootInvalid, &rootInvalid)
David Benjaminfd86eaa2020-06-17 15:13:16 -0400157
158 intermediateInvalid := intermediate
159 intermediateInvalid.template.ExtraExtensions = invalidExtension
David Benjamind1b20a92022-12-13 17:10:09 -0500160 mustGenerateCertificate(fmt.Sprintf("invalid_extension_intermediate_%s.pem", ext.name), &intermediateInvalid, &root)
David Benjaminfd86eaa2020-06-17 15:13:16 -0400161
162 leafInvalid := leaf
163 leafInvalid.template.ExtraExtensions = invalidExtension
David Benjamind1b20a92022-12-13 17:10:09 -0500164 mustGenerateCertificate(fmt.Sprintf("invalid_extension_leaf_%s.pem", ext.name), &leafInvalid, &intermediate)
David Benjamin491af102021-10-29 09:05:29 -0400165
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
David Benjamind1b20a92022-12-13 17:10:09 -0500182 mustGenerateCertificate(fmt.Sprintf("trailing_data_leaf_%s.pem", ext.name), &leafTrailingData, &intermediate)
David Benjaminfd86eaa2020-06-17 15:13:16 -0400183 }
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
David Benjamind1b20a92022-12-13 17:10:09 -0500204func mustParseECDSAKey(in string) *ecdsa.PrivateKey {
David Benjaminfd86eaa2020-06-17 15:13:16 -0400205 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}