github.com/microsoft/moc@v0.17.1/pkg/certs/util.go (about) 1 // Copyright (c) Microsoft Corporation. All rights reserved. 2 // Licensed under the Apache v2.0 license. 3 package certs 4 5 import ( 6 "bytes" 7 "crypto/rand" 8 "crypto/rsa" 9 "crypto/tls" 10 "crypto/x509" 11 "crypto/x509/pkix" 12 "encoding/pem" 13 "math" 14 "math/big" 15 "net" 16 "time" 17 18 "github.com/microsoft/moc/pkg/errors" 19 wssdnet "github.com/microsoft/moc/pkg/net" 20 ) 21 22 // KeyPair holds the raw bytes for a certificate and key. 23 type KeyPair struct { 24 Cert, Key []byte 25 } 26 27 // Config contains the basic fields required for creating a certificate. 28 type Config struct { 29 CommonName string 30 Organization []string 31 AltNames AltNames 32 Usages []x509.ExtKeyUsage 33 } 34 35 // Config contains the basic fields required for signing a certificate. 36 type SignConfig struct { 37 Offset time.Duration 38 Identity string 39 ServerAuth bool 40 IsCA bool 41 } 42 43 // AltNames contains the domain names and IP addresses for a cert 44 type AltNames struct { 45 DNSNames []string 46 IPs []net.IP 47 } 48 49 func publicKey(priv interface{}) interface{} { 50 switch k := priv.(type) { 51 case *rsa.PrivateKey: 52 return &k.PublicKey 53 default: 54 return nil 55 } 56 } 57 58 // IsValid returns true if both the certificate and key are non-nil. 59 func (k *KeyPair) IsValid() bool { 60 return k.Cert != nil && k.Key != nil 61 } 62 63 // NewPrivateKey creates an RSA private key 64 func NewPrivateKey() (*rsa.PrivateKey, error) { 65 pk, err := rsa.GenerateKey(rand.Reader, 2048) 66 return pk, err 67 } 68 69 // EncodeCertPEM returns PEM-endcoded certificate data. 70 func EncodeCertPEM(cert *x509.Certificate) []byte { 71 block := pem.Block{ 72 Type: "CERTIFICATE", 73 Bytes: cert.Raw, 74 } 75 return pem.EncodeToMemory(&block) 76 } 77 78 // EncodeCertRequestPEM returns PEM-endcoded certificate request data. 79 func EncodeCertRequestPEM(cert *x509.CertificateRequest) []byte { 80 block := pem.Block{ 81 Type: "CERTIFICATE REQUEST", 82 Bytes: cert.Raw, 83 } 84 return pem.EncodeToMemory(&block) 85 } 86 87 // EncodePrivateKeyPEM returns PEM-encoded private key data. 88 func EncodePrivateKeyPEM(key *rsa.PrivateKey) []byte { 89 block := pem.Block{ 90 Type: "RSA PRIVATE KEY", 91 Bytes: x509.MarshalPKCS1PrivateKey(key), 92 } 93 94 return pem.EncodeToMemory(&block) 95 } 96 97 // EncodePublicKeyPEM returns PEM-encoded public key data. 98 func EncodePublicKeyBytePEM(key []byte) ([]byte, error) { 99 block := pem.Block{ 100 Type: "PUBLIC KEY", 101 Bytes: key, 102 } 103 return pem.EncodeToMemory(&block), nil 104 } 105 106 // EncodePublicKeyPEM returns PEM-encoded public key data. 107 func EncodePublicKeyPEM(key *rsa.PublicKey) ([]byte, error) { 108 der, err := x509.MarshalPKIXPublicKey(key) 109 if err != nil { 110 return []byte{}, err 111 } 112 return EncodePublicKeyBytePEM(der) 113 } 114 115 // DecodeCertPEM attempts to return a decoded certificate or nil 116 // if the encoded input does not contain a certificate. 117 func DecodeCertPEM(encoded []byte) (*x509.Certificate, error) { 118 block, _ := pem.Decode(encoded) 119 if block == nil { 120 return nil, nil 121 } 122 123 return x509.ParseCertificate(block.Bytes) 124 } 125 126 // DecodeCertRequestPEM attempts to return a decoded certificate request or nil 127 // if the encoded input does not contain a certificate request. 128 func DecodeCertRequestPEM(encoded []byte) (*x509.CertificateRequest, error) { 129 block, _ := pem.Decode(encoded) 130 if block == nil { 131 return nil, nil 132 } 133 134 return x509.ParseCertificateRequest(block.Bytes) 135 } 136 137 // DecodePrivateKeyPEM attempts to return a decoded key or nil 138 // if the encoded input does not contain a private key. 139 func DecodePrivateKeyPEM(encoded []byte) (*rsa.PrivateKey, error) { 140 block, _ := pem.Decode(encoded) 141 if block == nil { 142 return nil, nil 143 } 144 145 return x509.ParsePKCS1PrivateKey(block.Bytes) 146 } 147 148 func GenerateClientCertificate(name string) (*x509.Certificate, *rsa.PrivateKey, error) { 149 key, err := rsa.GenerateKey(rand.Reader, 2048) 150 if err != nil { 151 return nil, key, err 152 } 153 154 nodeFqdn, err := wssdnet.GetIPAddress() 155 if err != nil { 156 return nil, key, err 157 } 158 159 now := time.Now().UTC() 160 161 serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) 162 if err != nil { 163 return nil, key, err 164 } 165 166 tmpl := x509.Certificate{ 167 SerialNumber: serial, 168 Subject: pkix.Name{ 169 CommonName: name, 170 Organization: []string{"microsoft"}, 171 }, 172 NotBefore: now.Add(time.Minute * -5), 173 NotAfter: now.Add(time.Hour * 24 * 365 * 10), // 10 years 174 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 175 MaxPathLenZero: true, 176 BasicConstraintsValid: true, 177 MaxPathLen: 0, 178 IsCA: true, 179 DNSNames: []string{"localhost"}, 180 IPAddresses: []net.IP{wssdnet.StringToNetIPAddress(wssdnet.LOOPBACK_ADDRESS), wssdnet.StringToNetIPAddress(nodeFqdn)}, 181 } 182 183 b, err := x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, key.Public(), key) 184 if err != nil { 185 return nil, key, err 186 } 187 188 x509Cert, err := x509.ParseCertificate(b) 189 if err != nil { 190 return nil, key, err 191 } 192 193 return x509Cert, key, nil 194 } 195 196 func NewSignedCert(key *rsa.PrivateKey, caCert *x509.Certificate, caKey *rsa.PrivateKey, conf Config) (*x509.Certificate, error) { 197 serial, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64)) 198 if err != nil { 199 return nil, err 200 } 201 202 now := time.Now().UTC() 203 204 tmpl := x509.Certificate{ 205 SerialNumber: serial, 206 Subject: pkix.Name{ 207 CommonName: conf.CommonName, 208 Organization: conf.Organization, 209 }, 210 NotBefore: now.Add(time.Minute * -5), 211 NotAfter: now.Add(time.Hour * 24 * 365), // 1 year 212 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, 213 ExtKeyUsage: conf.Usages, 214 BasicConstraintsValid: true, 215 DNSNames: conf.AltNames.DNSNames, 216 IPAddresses: conf.AltNames.IPs, 217 } 218 219 b, err := x509.CreateCertificate(rand.Reader, &tmpl, caCert, key.Public(), caKey) 220 if err != nil { 221 return nil, err 222 } 223 224 return x509.ParseCertificate(b) 225 } 226 227 // GenerateCertificateRequest creates a CSR 228 // if privKey is not provided, a new one will be created and returned 229 // if privKey is provided, it will be used to create csr and the same key will be returned 230 func GenerateCertificateRequest(conf *Config, privKey []byte) (csr []byte, retPrivKey []byte, err error) { 231 232 var key *rsa.PrivateKey 233 // It private key does not exist create a new key 234 if privKey == nil || len(privKey) == 0 { 235 key, err = rsa.GenerateKey(rand.Reader, 2048) 236 if err != nil { 237 return 238 } 239 retPrivKey = EncodePrivateKeyPEM(key) 240 } else { 241 key, err = DecodePrivateKeyPEM(privKey) 242 if err != nil { 243 return 244 } 245 retPrivKey = privKey 246 } 247 248 tmpl := x509.CertificateRequest{ 249 Subject: pkix.Name{ 250 CommonName: conf.CommonName, 251 Organization: conf.Organization, 252 }, 253 SignatureAlgorithm: x509.SHA256WithRSA, 254 PublicKey: key.Public(), 255 DNSNames: conf.AltNames.DNSNames, 256 IPAddresses: conf.AltNames.IPs, 257 } 258 259 b, err := x509.CreateCertificateRequest(rand.Reader, &tmpl, key) 260 if err != nil { 261 return 262 } 263 264 x509CertReq, err := x509.ParseCertificateRequest(b) 265 if err != nil { 266 return 267 } 268 269 csr = EncodeCertRequestPEM(x509CertReq) 270 271 return 272 } 273 274 func createCSRRenewExtensions(csrCertificate []byte, currentCertificate [][]byte) (extensions []pkix.Extension, err error) { 275 certsBuffer := bytes.Buffer{} 276 certPEMBlock := &pem.Block{ 277 Type: "CERTIFICATE", 278 Bytes: csrCertificate, 279 } 280 281 err = pem.Encode(&certsBuffer, certPEMBlock) 282 if err != nil { 283 return nil, errors.Wrapf(errors.Failed, "unable to PEM encode CSR certificate: %v", err) 284 } 285 286 for _, cert := range currentCertificate { 287 certPEMBlock.Bytes = cert 288 err = pem.Encode(&certsBuffer, certPEMBlock) 289 if err != nil { 290 return nil, errors.Wrapf(errors.Failed, "unable to PEM encode certificates: %v", err) 291 } 292 } 293 294 extensions = []pkix.Extension{ 295 { 296 Id: oidRenewCertificates, 297 Critical: false, 298 Value: certsBuffer.Bytes(), 299 }, 300 } 301 302 return extensions, nil 303 } 304 305 // GenerateCertificateRenewRequest creates a renew CSR 306 // A new private key will be created, used to create CSR and returned 307 func GenerateCertificateRenewRequest(cert *tls.Certificate) (retCsr []byte, retPriv []byte, err error) { 308 leaf := cert.Leaf 309 if leaf == nil { 310 leaf, err = x509.ParseCertificate(cert.Certificate[0]) 311 if err != nil { 312 return nil, nil, errors.Wrapf(errors.Failed, "unable to parse leaf: %v", err) 313 } 314 } 315 316 var privateKey *rsa.PrivateKey 317 318 switch pub := leaf.PublicKey.(type) { 319 case *rsa.PublicKey: 320 privateKey, err = rsa.GenerateKey(rand.Reader, pub.Size()*8) 321 default: 322 err = errors.Wrapf(errors.NotSupported, "unsupported public key type: %T", pub) 323 } 324 if err != nil { 325 return nil, nil, errors.Wrapf(errors.Failed, "unable to generate private key: %v", err) 326 } 327 retPriv = EncodePrivateKeyPEM(privateKey) 328 csrKeyTemplate := x509.Certificate{ 329 SerialNumber: big.NewInt(1), 330 Subject: pkix.Name{ 331 CommonName: "CSR Key", 332 }, 333 NotBefore: time.Now(), 334 NotAfter: leaf.NotAfter, 335 } 336 337 csrCertificate, err := x509.CreateCertificate(rand.Reader, &csrKeyTemplate, leaf, 338 privateKey.Public(), cert.PrivateKey) 339 if err != nil { 340 return nil, nil, errors.Wrapf(errors.Failed, "unable to create CSR Key certificate: %v", err) 341 } 342 343 csrTemplate := x509.CertificateRequest{ 344 Subject: leaf.Subject, 345 DNSNames: leaf.DNSNames, 346 IPAddresses: leaf.IPAddresses, 347 } 348 template := &csrTemplate 349 350 template.ExtraExtensions, err = createCSRRenewExtensions(csrCertificate, cert.Certificate) 351 if err != nil { 352 return nil, nil, errors.Wrapf(errors.Failed, "unable to create CSR renew extensions: %v", err) 353 } 354 355 csr, err := x509.CreateCertificateRequest(rand.Reader, template, privateKey) 356 if err != nil { 357 return nil, nil, errors.Wrapf(errors.Failed, "unable to create CSR request: %v", err) 358 } 359 360 x509CertReq, err := x509.ParseCertificateRequest(csr) 361 if err != nil { 362 return 363 } 364 retCsr = EncodeCertRequestPEM(x509CertReq) 365 return 366 } 367 368 // GenerateCertificateRenewRequestSameKey creates a renew CSR 369 // A same private key in cert will be used to create CSR 370 func GenerateCertificateRenewRequestSameKey(cert *tls.Certificate) (retCsr []byte, err error) { 371 372 leaf := cert.Leaf 373 if leaf == nil { 374 leaf, err = x509.ParseCertificate(cert.Certificate[0]) 375 if err != nil { 376 return nil, errors.Wrapf(errors.Failed, "unable to parse leaf: %v", err) 377 } 378 } 379 380 csrKeyTemplate := x509.Certificate{ 381 SerialNumber: big.NewInt(1), 382 Subject: pkix.Name{ 383 CommonName: "CSR Key", 384 }, 385 NotBefore: time.Now(), 386 NotAfter: leaf.NotAfter, 387 DNSNames: leaf.DNSNames, 388 IPAddresses: leaf.IPAddresses, 389 } 390 391 csrCertificate, err := x509.CreateCertificate(rand.Reader, &csrKeyTemplate, leaf, 392 publicKey(cert.PrivateKey), cert.PrivateKey) 393 if err != nil { 394 return nil, errors.Wrapf(errors.Failed, "unable to create CSR Key certificate: %v", err) 395 } 396 397 csrTemplate := x509.CertificateRequest{ 398 Subject: leaf.Subject, 399 DNSNames: leaf.DNSNames, 400 IPAddresses: leaf.IPAddresses, 401 } 402 template := &csrTemplate 403 404 template.ExtraExtensions, err = createCSRRenewExtensions(csrCertificate, cert.Certificate) 405 if err != nil { 406 return nil, errors.Wrapf(errors.Failed, "unable to create CSR renew extensions: %v", err) 407 } 408 409 csr, err := x509.CreateCertificateRequest(rand.Reader, template, cert.PrivateKey) 410 if err != nil { 411 return nil, errors.Wrapf(errors.Failed, "unable to create CSR request: %v", err) 412 } 413 414 x509CertReq, err := x509.ParseCertificateRequest(csr) 415 if err != nil { 416 return nil, err 417 } 418 retCsr = EncodeCertRequestPEM(x509CertReq) 419 return 420 }