12e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan/* Copyright (c) 2017, Google Inc. 22e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * 32e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * Permission to use, copy, modify, and/or distribute this software for any 42e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * purpose with or without fee is hereby granted, provided that the above 52e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * copyright notice and this permission notice appear in all copies. 62e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * 72e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 82e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 92e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 102e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 112e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 122e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 132e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 142e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 152e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan// make_many_constraints.go generates test certificates many_constraints.pem, 162e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan// many_names*.pem, and some_names*.pem for x509_test.cc 172e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanpackage main 182e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 192e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanimport ( 202e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "crypto/rand" 212e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "crypto/rsa" 222e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "crypto/x509" 232e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "crypto/x509/pkix" 242e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "encoding/asn1" 252e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "encoding/pem" 262e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "fmt" 272e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "math/big" 282e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "os" 292e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan "time" 302e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan) 312e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 322e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanconst privateKeyPEM = `-----BEGIN PRIVATE KEY----- 332e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC6C9qEGRIBQXV8 342e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanLj29vVu+U+tyXzSSinWIumK5ijPhCm3DLnv4RayxkFwemtnkGRZ/o94ZnsXkBfU/ 352e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanIlsYdkuq8wK9WI/ql3gwWjH+KARIhIQcSLGiJcLN6kGuG2nlRBKMcPgPiEq2B0yB 362e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanXFf4tG3CBbeae7+8G7uvOmv8NLyKj32neWpnUCTL5o2VwyPoxjLxT5gUR69v9XSV 372e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanFj2irCZbsEedeKSb++LqyMhLfnRTzNv+ZHNh4izZHrktR25MvnT5QyBq32hx7AjZ 382e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan2/xo70OmH7w10a2DwsVjJNMdxTEmgyvU9M6CeYRPX1Ykfg+sXCTtkTVAlBDUviIq 392e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanY95CKy25AgMBAAECggEAHPvvxRiqx2tNRFVn5QF1I4erbJwMcrADc5OmAcXYIz0e 402e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloansIOzaJBiQR9+Wn5BZ9nIuYXr+g3UQpvzAyz1CDCVxUIqsRj1AtUqMk4675+IW0vZ 412e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan0RY6Jkq/uJjANsGqk78xLJQE8VaIXSdx8c1THznsx4dgfT6+Ni4T5U6yuA33OZaw 422e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan4NdYZYtEkqNiqK6VYe4mAxxVh5qscihVVMGkBVqJNiiEotctm1lph8ow+7o8ggXO 432e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanW9xm+RHHPcH7Epx7hjkb/helANcYOK950W5/R+2zWV9R6kxo6R+/hfGFFmCvl4k5 442e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan+i8Y0IlEv3fze1E0Lwyf379i3C/cKcuaE5gwR54BAQKBgQDxlsNy9M37HgguglHt 452e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan8W+cuPNtxNjFCWIjNR9dSvdr1Oi28Z1AY+BBPSv6UBKnT5PpOFjqxfMY/j/zoKdI 462e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanaYX1phgeQHXcHrB1pS8yoaF/pTJSN2Yb8v9kl/Ch1yeYXaNVGmeBLkH9H6wIcUxD 472e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanMas1i8VUzshzhcluCNGoJj9wUQKBgQDFJOoWncssfWCrsuDWEoeU71Zh3+bD96GF 482e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloans29CdIbHpcbxhWYjA9RM8yxbGPopexzoGcV1HX6j8E1s0xfYZJV23rxoM9Zj9l5D 492e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanmZAJQPxYXIdu3h4PslhZLd3p+DEHjbsLC/avk3M4iZim1FMPBJMswKSL23ysqXoY 502e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan/ynor+W06QKBgHYeu6M6NHgCYAe1ai+Hq4WaHFNgOohkJRqHv7USkVSkvb+s9LDl 512e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan5GChcx4pBmXNj8ko5rirXkerEEOjGgdaqMfJlOM9qyKb0rVCtYfw5RCPCcKPGZqy 522e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanvdJGQ74tf0uNBO34QgE0R8lmMevS0XHNGCPPGgV0MSfikvD82N15De1xAoGAbsZM 532e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanRsMJfAlDPZc4oPEuf/BwMHTYPTsy5map2MSTSzGKdQHJH1myfD6TqOiDALXtyzlX 542e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan63PUShfn2YNPvcbe+Tk00rR1/htcYk2yUpDSenAbpZ9ncth6rjmInURZgG4SMKXb 552e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanSlLnBljCjtN1jFW8wQPKMc/14SslsVAHY3ka8KkCgYB58QNT1YfH3jS62+mT2pXq 562e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert SloanqLjLqvsD742VYnFoHR+HBOnN8ry0dda4lgwM106L5FgSg9DOZvASZ+QGFk+QVQv+ 572e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanc77ASWpuhmBmamZCrwZXrq9Xc92RDPkKFqnP9MVv06hYKNp0moSdM8dIaM6uSows 582e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan/r/aDs4oudubz26o5GDKmA== 592e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan-----END PRIVATE KEY-----` 602e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 612e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanvar privateKey *rsa.PrivateKey 622e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 632e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanfunc init() { 642e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan in := []byte(privateKeyPEM) 652e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan keyBlock, in := pem.Decode(in) 662e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if keyBlock == nil || keyBlock.Type != "PRIVATE KEY" { 672e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic("could not decode private key") 682e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 692e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan key, err := x509.ParsePKCS8PrivateKey(keyBlock.Bytes) 702e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if err != nil { 712e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 722e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 732e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan privateKey = key.(*rsa.PrivateKey) 742e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan} 752e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 762e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanfunc randOrDie(out []byte) { 772e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if _, err := rand.Reader.Read(out); err != nil { 782e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 792e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 802e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan} 812e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 822e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanfunc writePEM(path string, in []byte) { 832e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan file, err := os.Create(path) 842e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if err != nil { 852e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 862e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 872e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan defer file.Close() 882e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan err = pem.Encode(file, &pem.Block{Type: "CERTIFICATE", Bytes: in}) 892e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if err != nil { 902e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 912e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 922e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan} 932e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 942e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloanfunc main() { 952e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan notBefore, err := time.Parse(time.RFC3339, "2000-01-01T00:00:00Z") 962e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if err != nil { 972e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 982e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 992e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan notAfter, err := time.Parse(time.RFC3339, "2100-01-01T00:00:00Z") 1002e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if err != nil { 1012e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 1022e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1032e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 1042e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan caTemplate := x509.Certificate{ 1052e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan SerialNumber: new(big.Int).SetInt64(1), 1062e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan Subject: pkix.Name{CommonName: "CA"}, 1072e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan NotBefore: notBefore, 1082e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan NotAfter: notAfter, 1092e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan BasicConstraintsValid: true, 1102e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan IsCA: true, 1112e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 1122e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan KeyUsage: x509.KeyUsageCertSign, 1132e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan SignatureAlgorithm: x509.SHA256WithRSA, 1142e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1152e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan for i := 0; i < 513; i++ { 1162e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan caTemplate.ExcludedDNSDomains = append(caTemplate.ExcludedDNSDomains, fmt.Sprintf("x%d.test", i)) 1172e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1182e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan for i := 0; i < 513; i++ { 1192e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan caTemplate.PermittedDNSDomains = append(caTemplate.PermittedDNSDomains, fmt.Sprintf("t%d.test", i)) 1202e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1212e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan caTemplate.PermittedDNSDomains = append(caTemplate.PermittedDNSDomains, ".test") 1222e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan caBytes, err := x509.CreateCertificate(rand.Reader, &caTemplate, &caTemplate, &privateKey.PublicKey, privateKey) 1232e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if err != nil { 1242e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 1252e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1262e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan writePEM("many_constraints.pem", caBytes) 1272e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 1282e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan ca, err := x509.ParseCertificate(caBytes) 1292e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if err != nil { 1302e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 1312e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1322e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 1332e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan leaves := []struct { 1342e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan path string 1352e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan names int 1362e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan emails int 1372e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan }{ 1382e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan {"many_names1.pem", 513, 513}, 1392e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan {"many_names2.pem", 1025, 0}, 1402e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan {"many_names3.pem", 0, 1025}, 1412e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan {"some_names1.pem", 256, 256}, 1422e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan {"some_names2.pem", 513, 0}, 1432e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan {"some_names3.pem", 0, 513}, 1442e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1452e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan for i, leaf := range leaves { 1462e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan leafTemplate := x509.Certificate{ 1472e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan SerialNumber: new(big.Int).SetInt64(int64(i + 2)), 1482e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan Subject: pkix.Name{CommonName: "t0.test"}, 1492e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan NotBefore: notBefore, 1502e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan NotAfter: notAfter, 1512e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan BasicConstraintsValid: true, 1522e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan IsCA: false, 1532e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 1542e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, 1552e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan SignatureAlgorithm: x509.SHA256WithRSA, 1562e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1572e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan for i := 0; i < leaf.names; i++ { 1582e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan leafTemplate.DNSNames = append(leafTemplate.DNSNames, fmt.Sprintf("t%d.test", i)) 1592e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1602e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan for i := 0; i < leaf.emails; i++ { 1612e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan leafTemplate.Subject.ExtraNames = append(leafTemplate.Subject.ExtraNames, pkix.AttributeTypeAndValue{ 1622e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan Type: []int{1, 2, 840, 113549, 1, 9, 1}, 1632e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan Value: asn1.RawValue{ 1642e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan Class: asn1.ClassUniversal, 1652e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan Tag: asn1.TagIA5String, 1662e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan IsCompound: false, 1672e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan Bytes: []byte(fmt.Sprintf("t%d@test", i)), 1682e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan }, 1692e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan }) 1702e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1712e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan leafBytes, err := x509.CreateCertificate(rand.Reader, &leafTemplate, ca, &privateKey.PublicKey, privateKey) 1722e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan if err != nil { 1732e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan panic(err) 1742e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1752e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan 1762e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan writePEM(leaf.path, leafBytes) 1772e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan } 1782e9e66ad8f35ee615e79da22ff91b0fa94607ca8Robert Sloan} 179