github.com/rposudnevskiy/consul@v1.4.5/command/tls/generate.go (about) 1 package tls 2 3 import ( 4 "bytes" 5 "crypto" 6 "crypto/ecdsa" 7 "crypto/elliptic" 8 "crypto/rand" 9 "crypto/sha256" 10 "crypto/x509" 11 "crypto/x509/pkix" 12 "encoding/pem" 13 "fmt" 14 "math/big" 15 "net" 16 "strings" 17 "time" 18 ) 19 20 // GenerateSerialNumber returns random bigint generated with crypto/rand 21 func GenerateSerialNumber() (*big.Int, error) { 22 l := new(big.Int).Lsh(big.NewInt(1), 128) 23 s, err := rand.Int(rand.Reader, l) 24 if err != nil { 25 return nil, err 26 } 27 return s, nil 28 } 29 30 // GeneratePrivateKey generates a new ecdsa private key 31 func GeneratePrivateKey() (crypto.Signer, string, error) { 32 pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 33 if err != nil { 34 return nil, "", fmt.Errorf("error generating private key: %s", err) 35 } 36 37 bs, err := x509.MarshalECPrivateKey(pk) 38 if err != nil { 39 return nil, "", fmt.Errorf("error generating private key: %s", err) 40 } 41 42 var buf bytes.Buffer 43 err = pem.Encode(&buf, &pem.Block{Type: "EC PRIVATE KEY", Bytes: bs}) 44 if err != nil { 45 return nil, "", fmt.Errorf("error encoding private key: %s", err) 46 } 47 48 return pk, buf.String(), nil 49 } 50 51 // GenerateCA generates a new CA for agent TLS (not to be confused with Connect TLS) 52 func GenerateCA(signer crypto.Signer, sn *big.Int, days int, constraints []string) (string, error) { 53 id, err := keyID(signer.Public()) 54 if err != nil { 55 return "", err 56 } 57 58 name := fmt.Sprintf("Consul Agent CA %d", sn) 59 60 // Create the CA cert 61 template := x509.Certificate{ 62 SerialNumber: sn, 63 Subject: pkix.Name{ 64 Country: []string{"US"}, 65 PostalCode: []string{"94105"}, 66 Province: []string{"CA"}, 67 Locality: []string{"San Francisco"}, 68 StreetAddress: []string{"101 Second Street"}, 69 Organization: []string{"HashiCorp Inc."}, 70 CommonName: name, 71 }, 72 BasicConstraintsValid: true, 73 KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageDigitalSignature, 74 IsCA: true, 75 NotAfter: time.Now().AddDate(0, 0, days), 76 NotBefore: time.Now(), 77 AuthorityKeyId: id, 78 SubjectKeyId: id, 79 } 80 81 if len(constraints) > 0 { 82 template.PermittedDNSDomainsCritical = true 83 template.PermittedDNSDomains = constraints 84 } 85 bs, err := x509.CreateCertificate( 86 rand.Reader, &template, &template, signer.Public(), signer) 87 if err != nil { 88 return "", fmt.Errorf("error generating CA certificate: %s", err) 89 } 90 91 var buf bytes.Buffer 92 err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bs}) 93 if err != nil { 94 return "", fmt.Errorf("error encoding private key: %s", err) 95 } 96 97 return buf.String(), nil 98 } 99 100 // GenerateCert generates a new certificate for agent TLS (not to be confused with Connect TLS) 101 func GenerateCert(signer crypto.Signer, ca string, sn *big.Int, name string, days int, DNSNames []string, IPAddresses []net.IP, extKeyUsage []x509.ExtKeyUsage) (string, string, error) { 102 parent, err := parseCert(ca) 103 if err != nil { 104 return "", "", err 105 } 106 107 signee, pk, err := GeneratePrivateKey() 108 if err != nil { 109 return "", "", err 110 } 111 112 id, err := keyID(signee.Public()) 113 if err != nil { 114 return "", "", err 115 } 116 117 template := x509.Certificate{ 118 SerialNumber: sn, 119 Subject: pkix.Name{CommonName: name}, 120 BasicConstraintsValid: true, 121 KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, 122 ExtKeyUsage: extKeyUsage, 123 IsCA: false, 124 NotAfter: time.Now().AddDate(0, 0, days), 125 NotBefore: time.Now(), 126 SubjectKeyId: id, 127 DNSNames: DNSNames, 128 IPAddresses: IPAddresses, 129 } 130 131 bs, err := x509.CreateCertificate(rand.Reader, &template, parent, signee.Public(), signer) 132 if err != nil { 133 return "", "", err 134 } 135 136 var buf bytes.Buffer 137 err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: bs}) 138 if err != nil { 139 return "", "", fmt.Errorf("error encoding private key: %s", err) 140 } 141 142 return buf.String(), pk, nil 143 } 144 145 // KeyId returns a x509 KeyId from the given signing key. 146 func keyID(raw interface{}) ([]byte, error) { 147 switch raw.(type) { 148 case *ecdsa.PublicKey: 149 default: 150 return nil, fmt.Errorf("invalid key type: %T", raw) 151 } 152 153 // This is not standard; RFC allows any unique identifier as long as they 154 // match in subject/authority chains but suggests specific hashing of DER 155 // bytes of public key including DER tags. 156 bs, err := x509.MarshalPKIXPublicKey(raw) 157 if err != nil { 158 return nil, err 159 } 160 161 // String formatted 162 kID := sha256.Sum256(bs) 163 return []byte(strings.Replace(fmt.Sprintf("% x", kID), " ", ":", -1)), nil 164 } 165 166 func parseCert(pemValue string) (*x509.Certificate, error) { 167 // The _ result below is not an error but the remaining PEM bytes. 168 block, _ := pem.Decode([]byte(pemValue)) 169 if block == nil { 170 return nil, fmt.Errorf("no PEM-encoded data found") 171 } 172 173 if block.Type != "CERTIFICATE" { 174 return nil, fmt.Errorf("first PEM-block should be CERTIFICATE type") 175 } 176 177 return x509.ParseCertificate(block.Bytes) 178 } 179 180 // ParseSigner parses a crypto.Signer from a PEM-encoded key. The private key 181 // is expected to be the first block in the PEM value. 182 func ParseSigner(pemValue string) (crypto.Signer, error) { 183 // The _ result below is not an error but the remaining PEM bytes. 184 block, _ := pem.Decode([]byte(pemValue)) 185 if block == nil { 186 return nil, fmt.Errorf("no PEM-encoded data found") 187 } 188 189 switch block.Type { 190 case "EC PRIVATE KEY": 191 return x509.ParseECPrivateKey(block.Bytes) 192 default: 193 return nil, fmt.Errorf("unknown PEM block type for signing key: %s", block.Type) 194 } 195 } 196 197 func Verify(caString, certString, dns string) error { 198 roots := x509.NewCertPool() 199 ok := roots.AppendCertsFromPEM([]byte(caString)) 200 if !ok { 201 return fmt.Errorf("failed to parse root certificate") 202 } 203 204 cert, err := parseCert(certString) 205 if err != nil { 206 return fmt.Errorf("failed to parse certificate") 207 } 208 209 opts := x509.VerifyOptions{ 210 DNSName: fmt.Sprintf(dns), 211 Roots: roots, 212 } 213 214 _, err = cert.Verify(opts) 215 return err 216 }