1// Copyright 2020 The BoringSSL Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//go:build ignore
16
17// make_basic_constraints.go generates self-signed certificates with the basic
18// constraints extension.
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
33func main() {
34	key := ecdsaKeyFromPEMOrPanic(keyPEM)
35
36	notBefore, err := time.Parse(time.RFC3339, "2000-01-01T00:00:00Z")
37	if err != nil {
38		panic(err)
39	}
40	notAfter, err := time.Parse(time.RFC3339, "2100-01-01T00:00:00Z")
41	if err != nil {
42		panic(err)
43	}
44
45	baseTemplate := x509.Certificate{
46		SerialNumber:       new(big.Int).SetInt64(1),
47		Subject:            pkix.Name{CommonName: "Basic Constraints"},
48		NotBefore:          notBefore,
49		NotAfter:           notAfter,
50		SignatureAlgorithm: x509.ECDSAWithSHA256,
51	}
52
53	certs := []struct {
54		name                  string
55		basicConstraintsValid bool
56		isCA                  bool
57		maxPathLen            int
58		maxPathLenZero        bool
59	}{
60		{name: "none"},
61		{name: "leaf", basicConstraintsValid: true},
62		{name: "ca", basicConstraintsValid: true, isCA: true},
63		{name: "ca_pathlen_0", basicConstraintsValid: true, isCA: true, maxPathLenZero: true},
64		{name: "ca_pathlen_1", basicConstraintsValid: true, isCA: true, maxPathLen: 1},
65		{name: "ca_pathlen_10", basicConstraintsValid: true, isCA: true, maxPathLen: 10},
66	}
67	for _, cert := range certs {
68		template := baseTemplate
69		template.BasicConstraintsValid = cert.basicConstraintsValid
70		template.IsCA = cert.isCA
71		template.MaxPathLen = cert.maxPathLen
72		template.MaxPathLenZero = cert.maxPathLenZero
73
74		certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
75		if err != nil {
76			panic(err)
77		}
78
79		certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
80		if err := os.WriteFile(fmt.Sprintf("basic_constraints_%s.pem", cert.name), certPEM, 0666); err != nil {
81			panic(err)
82		}
83	}
84}
85
86const keyPEM = `-----BEGIN PRIVATE KEY-----
87MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoPUXNXuH9mgiS/nk
88024SYxryxMa3CyGJldiHymLxSquhRANCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5
89w8u3SSwm7HZREvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5X
90-----END PRIVATE KEY-----`
91
92func ecdsaKeyFromPEMOrPanic(in string) *ecdsa.PrivateKey {
93	keyBlock, _ := pem.Decode([]byte(in))
94	if keyBlock == nil || keyBlock.Type != "PRIVATE KEY" {
95		panic("could not decode private key")
96	}
97	key, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
98	if err != nil {
99		panic(err)
100	}
101	return key.(*ecdsa.PrivateKey)
102}
103