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// make_basic_constraints.go generates self-signed certificates with the basic 16// constraints extension. 17package main 18 19import ( 20 "crypto/ecdsa" 21 "crypto/rand" 22 "crypto/x509" 23 "crypto/x509/pkix" 24 "encoding/pem" 25 "fmt" 26 "io/ioutil" 27 "math/big" 28 "time" 29) 30 31func main() { 32 key := ecdsaKeyFromPEMOrPanic(keyPEM) 33 34 notBefore, err := time.Parse(time.RFC3339, "2000-01-01T00:00:00Z") 35 if err != nil { 36 panic(err) 37 } 38 notAfter, err := time.Parse(time.RFC3339, "2100-01-01T00:00:00Z") 39 if err != nil { 40 panic(err) 41 } 42 43 baseTemplate := x509.Certificate{ 44 SerialNumber: new(big.Int).SetInt64(1), 45 Subject: pkix.Name{CommonName: "Basic Constraints"}, 46 NotBefore: notBefore, 47 NotAfter: notAfter, 48 SignatureAlgorithm: x509.ECDSAWithSHA256, 49 } 50 51 certs := []struct { 52 name string 53 basicConstraintsValid bool 54 isCA bool 55 maxPathLen int 56 maxPathLenZero bool 57 }{ 58 {name: "none"}, 59 {name: "leaf", basicConstraintsValid: true}, 60 {name: "ca", basicConstraintsValid: true, isCA: true}, 61 {name: "ca_pathlen_0", basicConstraintsValid: true, isCA: true, maxPathLenZero: true}, 62 {name: "ca_pathlen_1", basicConstraintsValid: true, isCA: true, maxPathLen: 1}, 63 {name: "ca_pathlen_10", basicConstraintsValid: true, isCA: true, maxPathLen: 10}, 64 } 65 for _, cert := range certs { 66 template := baseTemplate 67 template.BasicConstraintsValid = cert.basicConstraintsValid 68 template.IsCA = cert.isCA 69 template.MaxPathLen = cert.maxPathLen 70 template.MaxPathLenZero = cert.maxPathLenZero 71 72 certBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) 73 if err != nil { 74 panic(err) 75 } 76 77 certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes}) 78 if err := ioutil.WriteFile(fmt.Sprintf("basic_constraints_%s.pem", cert.name), certPEM, 0666); err != nil { 79 panic(err) 80 } 81 } 82} 83 84const keyPEM = `-----BEGIN PRIVATE KEY----- 85MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoPUXNXuH9mgiS/nk 86024SYxryxMa3CyGJldiHymLxSquhRANCAASRKti8VW2Rkma+Kt9jQkMNitlCs0l5 87w8u3SSwm7HZREvmcBCJBjVIREacRqI0umhzR2V5NLzBBP9yPD/A+Ch5X 88-----END PRIVATE KEY-----` 89 90func ecdsaKeyFromPEMOrPanic(in string) *ecdsa.PrivateKey { 91 keyBlock, _ := pem.Decode([]byte(in)) 92 if keyBlock == nil || keyBlock.Type != "PRIVATE KEY" { 93 panic("could not decode private key") 94 } 95 key, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes) 96 if err != nil { 97 panic(err) 98 } 99 return key.(*ecdsa.PrivateKey) 100} 101