• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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