1// Package certutil contains helper functions that are mostly used 2// with the PKI backend but can be generally useful. Functionality 3// includes helpers for converting a certificate/private key bundle 4// between DER and PEM, printing certificate serial numbers, and more. 5// 6// Functionality specific to the PKI backend includes some types 7// and helper methods to make requesting certificates from the 8// backend easy. 9package certutil 10 11import ( 12 "bytes" 13 "crypto" 14 "crypto/ecdsa" 15 "crypto/rsa" 16 "crypto/tls" 17 "crypto/x509" 18 "crypto/x509/pkix" 19 "encoding/pem" 20 "fmt" 21 "math/big" 22 "net" 23 "net/url" 24 "strings" 25 "time" 26 27 "github.com/hashicorp/errwrap" 28 "github.com/hashicorp/vault/sdk/helper/errutil" 29) 30 31const ( 32 PrivateKeyTypeP521 = "p521" 33) 34 35// This can be one of a few key types so the different params may or may not be filled 36type ClusterKeyParams struct { 37 Type string `json:"type" structs:"type" mapstructure:"type"` 38 X *big.Int `json:"x" structs:"x" mapstructure:"x"` 39 Y *big.Int `json:"y" structs:"y" mapstructure:"y"` 40 D *big.Int `json:"d" structs:"d" mapstructure:"d"` 41} 42 43// Secret is used to attempt to unmarshal a Vault secret 44// JSON response, as a convenience 45type Secret struct { 46 Data map[string]interface{} `json:"data"` 47} 48 49// PrivateKeyType holds a string representation of the type of private key (ec 50// or rsa) referenced in CertBundle and ParsedCertBundle. This uses colloquial 51// names rather than official names, to eliminate confusion 52type PrivateKeyType string 53 54// Well-known PrivateKeyTypes 55const ( 56 UnknownPrivateKey PrivateKeyType = "" 57 RSAPrivateKey PrivateKeyType = "rsa" 58 ECPrivateKey PrivateKeyType = "ec" 59) 60 61// TLSUsage controls whether the intended usage of a *tls.Config 62// returned from ParsedCertBundle.getTLSConfig is for server use, 63// client use, or both, which affects which values are set 64type TLSUsage int 65 66// Well-known TLSUsage types 67const ( 68 TLSUnknown TLSUsage = 0 69 TLSServer TLSUsage = 1 << iota 70 TLSClient 71) 72 73// BlockType indicates the serialization format of the key 74type BlockType string 75 76// Well-known formats 77const ( 78 PKCS1Block BlockType = "RSA PRIVATE KEY" 79 PKCS8Block BlockType = "PRIVATE KEY" 80 ECBlock BlockType = "EC PRIVATE KEY" 81) 82 83// ParsedPrivateKeyContainer allows common key setting for certs and CSRs 84type ParsedPrivateKeyContainer interface { 85 SetParsedPrivateKey(crypto.Signer, PrivateKeyType, []byte) 86} 87 88// CertBlock contains the DER-encoded certificate and the PEM 89// block's byte array 90type CertBlock struct { 91 Certificate *x509.Certificate 92 Bytes []byte 93} 94 95// CertBundle contains a key type, a PEM-encoded private key, 96// a PEM-encoded certificate, and a string-encoded serial number, 97// returned from a successful Issue request 98type CertBundle struct { 99 PrivateKeyType PrivateKeyType `json:"private_key_type" structs:"private_key_type" mapstructure:"private_key_type"` 100 Certificate string `json:"certificate" structs:"certificate" mapstructure:"certificate"` 101 IssuingCA string `json:"issuing_ca" structs:"issuing_ca" mapstructure:"issuing_ca"` 102 CAChain []string `json:"ca_chain" structs:"ca_chain" mapstructure:"ca_chain"` 103 PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"` 104 SerialNumber string `json:"serial_number" structs:"serial_number" mapstructure:"serial_number"` 105} 106 107// ParsedCertBundle contains a key type, a DER-encoded private key, 108// and a DER-encoded certificate 109type ParsedCertBundle struct { 110 PrivateKeyType PrivateKeyType 111 PrivateKeyFormat BlockType 112 PrivateKeyBytes []byte 113 PrivateKey crypto.Signer 114 CertificateBytes []byte 115 Certificate *x509.Certificate 116 CAChain []*CertBlock 117} 118 119// CSRBundle contains a key type, a PEM-encoded private key, 120// and a PEM-encoded CSR 121type CSRBundle struct { 122 PrivateKeyType PrivateKeyType `json:"private_key_type" structs:"private_key_type" mapstructure:"private_key_type"` 123 CSR string `json:"csr" structs:"csr" mapstructure:"csr"` 124 PrivateKey string `json:"private_key" structs:"private_key" mapstructure:"private_key"` 125} 126 127// ParsedCSRBundle contains a key type, a DER-encoded private key, 128// and a DER-encoded certificate request 129type ParsedCSRBundle struct { 130 PrivateKeyType PrivateKeyType 131 PrivateKeyBytes []byte 132 PrivateKey crypto.Signer 133 CSRBytes []byte 134 CSR *x509.CertificateRequest 135} 136 137// ToPEMBundle converts a string-based certificate bundle 138// to a PEM-based string certificate bundle in trust path 139// order, leaf certificate first 140func (c *CertBundle) ToPEMBundle() string { 141 var result []string 142 143 if len(c.PrivateKey) > 0 { 144 result = append(result, c.PrivateKey) 145 } 146 if len(c.Certificate) > 0 { 147 result = append(result, c.Certificate) 148 } 149 if len(c.CAChain) > 0 { 150 result = append(result, c.CAChain...) 151 } 152 153 return strings.Join(result, "\n") 154} 155 156// ToParsedCertBundle converts a string-based certificate bundle 157// to a byte-based raw certificate bundle 158func (c *CertBundle) ToParsedCertBundle() (*ParsedCertBundle, error) { 159 result := &ParsedCertBundle{} 160 var err error 161 var pemBlock *pem.Block 162 163 if len(c.PrivateKey) > 0 { 164 pemBlock, _ = pem.Decode([]byte(c.PrivateKey)) 165 if pemBlock == nil { 166 return nil, errutil.UserError{Err: "Error decoding private key from cert bundle"} 167 } 168 169 result.PrivateKeyBytes = pemBlock.Bytes 170 result.PrivateKeyFormat = BlockType(strings.TrimSpace(pemBlock.Type)) 171 172 switch result.PrivateKeyFormat { 173 case ECBlock: 174 result.PrivateKeyType, c.PrivateKeyType = ECPrivateKey, ECPrivateKey 175 case PKCS1Block: 176 c.PrivateKeyType, result.PrivateKeyType = RSAPrivateKey, RSAPrivateKey 177 case PKCS8Block: 178 t, err := getPKCS8Type(pemBlock.Bytes) 179 if err != nil { 180 return nil, errutil.UserError{Err: fmt.Sprintf("Error getting key type from pkcs#8: %v", err)} 181 } 182 result.PrivateKeyType = t 183 switch t { 184 case ECPrivateKey: 185 c.PrivateKeyType = ECPrivateKey 186 case RSAPrivateKey: 187 c.PrivateKeyType = RSAPrivateKey 188 } 189 default: 190 return nil, errutil.UserError{Err: fmt.Sprintf("Unsupported key block type: %s", pemBlock.Type)} 191 } 192 193 result.PrivateKey, err = result.getSigner() 194 if err != nil { 195 return nil, errutil.UserError{Err: fmt.Sprintf("Error getting signer: %s", err)} 196 } 197 } 198 199 if len(c.Certificate) > 0 { 200 pemBlock, _ = pem.Decode([]byte(c.Certificate)) 201 if pemBlock == nil { 202 return nil, errutil.UserError{Err: "Error decoding certificate from cert bundle"} 203 } 204 result.CertificateBytes = pemBlock.Bytes 205 result.Certificate, err = x509.ParseCertificate(result.CertificateBytes) 206 if err != nil { 207 return nil, errutil.UserError{Err: fmt.Sprintf("Error encountered parsing certificate bytes from raw bundle: %v", err)} 208 } 209 } 210 switch { 211 case len(c.CAChain) > 0: 212 for _, cert := range c.CAChain { 213 pemBlock, _ := pem.Decode([]byte(cert)) 214 if pemBlock == nil { 215 return nil, errutil.UserError{Err: "Error decoding certificate from cert bundle"} 216 } 217 218 parsedCert, err := x509.ParseCertificate(pemBlock.Bytes) 219 if err != nil { 220 return nil, errutil.UserError{Err: fmt.Sprintf("Error encountered parsing certificate bytes from raw bundle via CA chain: %v", err)} 221 } 222 223 certBlock := &CertBlock{ 224 Bytes: pemBlock.Bytes, 225 Certificate: parsedCert, 226 } 227 result.CAChain = append(result.CAChain, certBlock) 228 } 229 230 // For backwards compatibility 231 case len(c.IssuingCA) > 0: 232 pemBlock, _ = pem.Decode([]byte(c.IssuingCA)) 233 if pemBlock == nil { 234 return nil, errutil.UserError{Err: "Error decoding ca certificate from cert bundle"} 235 } 236 237 parsedCert, err := x509.ParseCertificate(pemBlock.Bytes) 238 if err != nil { 239 return nil, errutil.UserError{Err: fmt.Sprintf("Error encountered parsing certificate bytes from raw bundle via issuing CA: %v", err)} 240 } 241 242 certBlock := &CertBlock{ 243 Bytes: pemBlock.Bytes, 244 Certificate: parsedCert, 245 } 246 result.CAChain = append(result.CAChain, certBlock) 247 } 248 249 // Populate if it isn't there already 250 if len(c.SerialNumber) == 0 && len(c.Certificate) > 0 { 251 c.SerialNumber = GetHexFormatted(result.Certificate.SerialNumber.Bytes(), ":") 252 } 253 254 return result, nil 255} 256 257// ToCertBundle converts a byte-based raw DER certificate bundle 258// to a PEM-based string certificate bundle 259func (p *ParsedCertBundle) ToCertBundle() (*CertBundle, error) { 260 result := &CertBundle{} 261 block := pem.Block{ 262 Type: "CERTIFICATE", 263 } 264 265 if p.Certificate != nil { 266 result.SerialNumber = strings.TrimSpace(GetHexFormatted(p.Certificate.SerialNumber.Bytes(), ":")) 267 } 268 269 if p.CertificateBytes != nil && len(p.CertificateBytes) > 0 { 270 block.Bytes = p.CertificateBytes 271 result.Certificate = strings.TrimSpace(string(pem.EncodeToMemory(&block))) 272 } 273 274 for _, caCert := range p.CAChain { 275 block.Bytes = caCert.Bytes 276 certificate := strings.TrimSpace(string(pem.EncodeToMemory(&block))) 277 278 result.CAChain = append(result.CAChain, certificate) 279 } 280 281 if p.PrivateKeyBytes != nil && len(p.PrivateKeyBytes) > 0 { 282 block.Type = string(p.PrivateKeyFormat) 283 block.Bytes = p.PrivateKeyBytes 284 result.PrivateKeyType = p.PrivateKeyType 285 286 // Handle bundle not parsed by us 287 if block.Type == "" { 288 switch p.PrivateKeyType { 289 case ECPrivateKey: 290 block.Type = string(ECBlock) 291 case RSAPrivateKey: 292 block.Type = string(PKCS1Block) 293 } 294 } 295 296 result.PrivateKey = strings.TrimSpace(string(pem.EncodeToMemory(&block))) 297 } 298 299 return result, nil 300} 301 302// Verify checks if the parsed bundle is valid. It validates the public 303// key of the certificate to the private key and checks the certificate trust 304// chain for path issues. 305func (p *ParsedCertBundle) Verify() error { 306 // If private key exists, check if it matches the public key of cert 307 if p.PrivateKey != nil && p.Certificate != nil { 308 equal, err := ComparePublicKeys(p.Certificate.PublicKey, p.PrivateKey.Public()) 309 if err != nil { 310 return errwrap.Wrapf("could not compare public and private keys: {{err}}", err) 311 } 312 if !equal { 313 return fmt.Errorf("public key of certificate does not match private key") 314 } 315 } 316 317 certPath := p.GetCertificatePath() 318 if len(certPath) > 1 { 319 for i, caCert := range certPath[1:] { 320 if !caCert.Certificate.IsCA { 321 return fmt.Errorf("certificate %d of certificate chain is not a certificate authority", i+1) 322 } 323 if !bytes.Equal(certPath[i].Certificate.AuthorityKeyId, caCert.Certificate.SubjectKeyId) { 324 return fmt.Errorf("certificate %d of certificate chain ca trust path is incorrect (%q/%q) (%X/%X)", 325 i+1, 326 certPath[i].Certificate.Subject.CommonName, caCert.Certificate.Subject.CommonName, 327 certPath[i].Certificate.AuthorityKeyId, caCert.Certificate.SubjectKeyId) 328 } 329 } 330 } 331 332 return nil 333} 334 335// GetCertificatePath returns a slice of certificates making up a path, pulled 336// from the parsed cert bundle 337func (p *ParsedCertBundle) GetCertificatePath() []*CertBlock { 338 var certPath []*CertBlock 339 340 certPath = append(certPath, &CertBlock{ 341 Certificate: p.Certificate, 342 Bytes: p.CertificateBytes, 343 }) 344 345 if len(p.CAChain) > 0 { 346 // Root CA puts itself in the chain 347 if p.CAChain[0].Certificate.SerialNumber != p.Certificate.SerialNumber { 348 certPath = append(certPath, p.CAChain...) 349 } 350 } 351 352 return certPath 353} 354 355// GetSigner returns a crypto.Signer corresponding to the private key 356// contained in this ParsedCertBundle. The Signer contains a Public() function 357// for getting the corresponding public. The Signer can also be 358// type-converted to private keys 359func (p *ParsedCertBundle) getSigner() (crypto.Signer, error) { 360 var signer crypto.Signer 361 var err error 362 363 if p.PrivateKeyBytes == nil || len(p.PrivateKeyBytes) == 0 { 364 return nil, errutil.UserError{Err: "Given parsed cert bundle does not have private key information"} 365 } 366 367 switch p.PrivateKeyFormat { 368 case ECBlock: 369 signer, err = x509.ParseECPrivateKey(p.PrivateKeyBytes) 370 if err != nil { 371 return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private EC key: %s", err)} 372 } 373 374 case PKCS1Block: 375 signer, err = x509.ParsePKCS1PrivateKey(p.PrivateKeyBytes) 376 if err != nil { 377 return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private RSA key: %s", err)} 378 } 379 380 case PKCS8Block: 381 if k, err := x509.ParsePKCS8PrivateKey(p.PrivateKeyBytes); err == nil { 382 switch k := k.(type) { 383 case *rsa.PrivateKey, *ecdsa.PrivateKey: 384 return k.(crypto.Signer), nil 385 default: 386 return nil, errutil.UserError{Err: "Found unknown private key type in pkcs#8 wrapping"} 387 } 388 } 389 return nil, errutil.UserError{Err: fmt.Sprintf("Failed to parse pkcs#8 key: %v", err)} 390 default: 391 return nil, errutil.UserError{Err: "Unable to determine type of private key; only RSA and EC are supported"} 392 } 393 return signer, nil 394} 395 396// SetParsedPrivateKey sets the private key parameters on the bundle 397func (p *ParsedCertBundle) SetParsedPrivateKey(privateKey crypto.Signer, privateKeyType PrivateKeyType, privateKeyBytes []byte) { 398 p.PrivateKey = privateKey 399 p.PrivateKeyType = privateKeyType 400 p.PrivateKeyBytes = privateKeyBytes 401} 402 403func getPKCS8Type(bs []byte) (PrivateKeyType, error) { 404 k, err := x509.ParsePKCS8PrivateKey(bs) 405 if err != nil { 406 return UnknownPrivateKey, errutil.UserError{Err: fmt.Sprintf("Failed to parse pkcs#8 key: %v", err)} 407 } 408 409 switch k.(type) { 410 case *ecdsa.PrivateKey: 411 return ECPrivateKey, nil 412 case *rsa.PrivateKey: 413 return RSAPrivateKey, nil 414 default: 415 return UnknownPrivateKey, errutil.UserError{Err: "Found unknown private key type in pkcs#8 wrapping"} 416 } 417} 418 419// ToParsedCSRBundle converts a string-based CSR bundle 420// to a byte-based raw CSR bundle 421func (c *CSRBundle) ToParsedCSRBundle() (*ParsedCSRBundle, error) { 422 result := &ParsedCSRBundle{} 423 var err error 424 var pemBlock *pem.Block 425 426 if len(c.PrivateKey) > 0 { 427 pemBlock, _ = pem.Decode([]byte(c.PrivateKey)) 428 if pemBlock == nil { 429 return nil, errutil.UserError{Err: "Error decoding private key from cert bundle"} 430 } 431 result.PrivateKeyBytes = pemBlock.Bytes 432 433 switch BlockType(pemBlock.Type) { 434 case ECBlock: 435 result.PrivateKeyType = ECPrivateKey 436 case PKCS1Block: 437 result.PrivateKeyType = RSAPrivateKey 438 default: 439 // Try to figure it out and correct 440 if _, err := x509.ParseECPrivateKey(pemBlock.Bytes); err == nil { 441 result.PrivateKeyType = ECPrivateKey 442 c.PrivateKeyType = "ec" 443 } else if _, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes); err == nil { 444 result.PrivateKeyType = RSAPrivateKey 445 c.PrivateKeyType = "rsa" 446 } else { 447 return nil, errutil.UserError{Err: fmt.Sprintf("Unknown private key type in bundle: %s", c.PrivateKeyType)} 448 } 449 } 450 451 result.PrivateKey, err = result.getSigner() 452 if err != nil { 453 return nil, errutil.UserError{Err: fmt.Sprintf("Error getting signer: %s", err)} 454 } 455 } 456 457 if len(c.CSR) > 0 { 458 pemBlock, _ = pem.Decode([]byte(c.CSR)) 459 if pemBlock == nil { 460 return nil, errutil.UserError{Err: "Error decoding certificate from cert bundle"} 461 } 462 result.CSRBytes = pemBlock.Bytes 463 result.CSR, err = x509.ParseCertificateRequest(result.CSRBytes) 464 if err != nil { 465 return nil, errutil.UserError{Err: fmt.Sprintf("Error encountered parsing certificate bytes from raw bundle via CSR: %v", err)} 466 } 467 } 468 469 return result, nil 470} 471 472// ToCSRBundle converts a byte-based raw DER certificate bundle 473// to a PEM-based string certificate bundle 474func (p *ParsedCSRBundle) ToCSRBundle() (*CSRBundle, error) { 475 result := &CSRBundle{} 476 block := pem.Block{ 477 Type: "CERTIFICATE REQUEST", 478 } 479 480 if p.CSRBytes != nil && len(p.CSRBytes) > 0 { 481 block.Bytes = p.CSRBytes 482 result.CSR = strings.TrimSpace(string(pem.EncodeToMemory(&block))) 483 } 484 485 if p.PrivateKeyBytes != nil && len(p.PrivateKeyBytes) > 0 { 486 block.Bytes = p.PrivateKeyBytes 487 switch p.PrivateKeyType { 488 case RSAPrivateKey: 489 result.PrivateKeyType = "rsa" 490 block.Type = "RSA PRIVATE KEY" 491 case ECPrivateKey: 492 result.PrivateKeyType = "ec" 493 block.Type = "EC PRIVATE KEY" 494 default: 495 return nil, errutil.InternalError{Err: "Could not determine private key type when creating block"} 496 } 497 result.PrivateKey = strings.TrimSpace(string(pem.EncodeToMemory(&block))) 498 } 499 500 return result, nil 501} 502 503// GetSigner returns a crypto.Signer corresponding to the private key 504// contained in this ParsedCSRBundle. The Signer contains a Public() function 505// for getting the corresponding public. The Signer can also be 506// type-converted to private keys 507func (p *ParsedCSRBundle) getSigner() (crypto.Signer, error) { 508 var signer crypto.Signer 509 var err error 510 511 if p.PrivateKeyBytes == nil || len(p.PrivateKeyBytes) == 0 { 512 return nil, errutil.UserError{Err: "Given parsed cert bundle does not have private key information"} 513 } 514 515 switch p.PrivateKeyType { 516 case ECPrivateKey: 517 signer, err = x509.ParseECPrivateKey(p.PrivateKeyBytes) 518 if err != nil { 519 return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private EC key: %s", err)} 520 } 521 522 case RSAPrivateKey: 523 signer, err = x509.ParsePKCS1PrivateKey(p.PrivateKeyBytes) 524 if err != nil { 525 return nil, errutil.UserError{Err: fmt.Sprintf("Unable to parse CA's private RSA key: %s", err)} 526 } 527 528 default: 529 return nil, errutil.UserError{Err: "Unable to determine type of private key; only RSA and EC are supported"} 530 } 531 return signer, nil 532} 533 534// SetParsedPrivateKey sets the private key parameters on the bundle 535func (p *ParsedCSRBundle) SetParsedPrivateKey(privateKey crypto.Signer, privateKeyType PrivateKeyType, privateKeyBytes []byte) { 536 p.PrivateKey = privateKey 537 p.PrivateKeyType = privateKeyType 538 p.PrivateKeyBytes = privateKeyBytes 539} 540 541// getTLSConfig returns a TLS config generally suitable for client 542// authentication. The returned TLS config can be modified slightly 543// to be made suitable for a server requiring client authentication; 544// specifically, you should set the value of ClientAuth in the returned 545// config to match your needs. 546func (p *ParsedCertBundle) GetTLSConfig(usage TLSUsage) (*tls.Config, error) { 547 tlsCert := tls.Certificate{ 548 Certificate: [][]byte{}, 549 } 550 551 tlsConfig := &tls.Config{ 552 MinVersion: tls.VersionTLS12, 553 } 554 555 if p.Certificate != nil { 556 tlsCert.Leaf = p.Certificate 557 } 558 559 if p.PrivateKey != nil { 560 tlsCert.PrivateKey = p.PrivateKey 561 } 562 563 if p.CertificateBytes != nil && len(p.CertificateBytes) > 0 { 564 tlsCert.Certificate = append(tlsCert.Certificate, p.CertificateBytes) 565 } 566 567 if len(p.CAChain) > 0 { 568 for _, cert := range p.CAChain { 569 tlsCert.Certificate = append(tlsCert.Certificate, cert.Bytes) 570 } 571 572 // Technically we only need one cert, but this doesn't duplicate code 573 certBundle, err := p.ToCertBundle() 574 if err != nil { 575 return nil, errwrap.Wrapf("error converting parsed bundle to string bundle when getting TLS config: {{err}}", err) 576 } 577 578 caPool := x509.NewCertPool() 579 ok := caPool.AppendCertsFromPEM([]byte(certBundle.CAChain[0])) 580 if !ok { 581 return nil, fmt.Errorf("could not append CA certificate") 582 } 583 584 if usage&TLSServer > 0 { 585 tlsConfig.ClientCAs = caPool 586 tlsConfig.ClientAuth = tls.VerifyClientCertIfGiven 587 } 588 if usage&TLSClient > 0 { 589 tlsConfig.RootCAs = caPool 590 } 591 } 592 593 if tlsCert.Certificate != nil && len(tlsCert.Certificate) > 0 { 594 tlsConfig.Certificates = []tls.Certificate{tlsCert} 595 tlsConfig.BuildNameToCertificate() 596 } 597 598 return tlsConfig, nil 599} 600 601// IssueData is a structure that is suitable for marshaling into a request; 602// either via JSON, or into a map[string]interface{} via the structs package 603type IssueData struct { 604 TTL string `json:"ttl" structs:"ttl" mapstructure:"ttl"` 605 CommonName string `json:"common_name" structs:"common_name" mapstructure:"common_name"` 606 OU string `json:"ou" structs:"ou" mapstructure:"ou"` 607 AltNames string `json:"alt_names" structs:"alt_names" mapstructure:"alt_names"` 608 IPSANs string `json:"ip_sans" structs:"ip_sans" mapstructure:"ip_sans"` 609 CSR string `json:"csr" structs:"csr" mapstructure:"csr"` 610 OtherSANs string `json:"other_sans" structs:"other_sans" mapstructure:"other_sans"` 611} 612 613type URLEntries struct { 614 IssuingCertificates []string `json:"issuing_certificates" structs:"issuing_certificates" mapstructure:"issuing_certificates"` 615 CRLDistributionPoints []string `json:"crl_distribution_points" structs:"crl_distribution_points" mapstructure:"crl_distribution_points"` 616 OCSPServers []string `json:"ocsp_servers" structs:"ocsp_servers" mapstructure:"ocsp_servers"` 617} 618 619type CAInfoBundle struct { 620 ParsedCertBundle 621 URLs *URLEntries 622} 623 624func (b *CAInfoBundle) GetCAChain() []*CertBlock { 625 chain := []*CertBlock{} 626 627 // Include issuing CA in Chain, not including Root Authority 628 if (len(b.Certificate.AuthorityKeyId) > 0 && 629 !bytes.Equal(b.Certificate.AuthorityKeyId, b.Certificate.SubjectKeyId)) || 630 (len(b.Certificate.AuthorityKeyId) == 0 && 631 !bytes.Equal(b.Certificate.RawIssuer, b.Certificate.RawSubject)) { 632 633 chain = append(chain, &CertBlock{ 634 Certificate: b.Certificate, 635 Bytes: b.CertificateBytes, 636 }) 637 if b.CAChain != nil && len(b.CAChain) > 0 { 638 chain = append(chain, b.CAChain...) 639 } 640 } 641 642 return chain 643} 644 645type CertExtKeyUsage int 646 647const ( 648 AnyExtKeyUsage CertExtKeyUsage = 1 << iota 649 ServerAuthExtKeyUsage 650 ClientAuthExtKeyUsage 651 CodeSigningExtKeyUsage 652 EmailProtectionExtKeyUsage 653 IpsecEndSystemExtKeyUsage 654 IpsecTunnelExtKeyUsage 655 IpsecUserExtKeyUsage 656 TimeStampingExtKeyUsage 657 OcspSigningExtKeyUsage 658 MicrosoftServerGatedCryptoExtKeyUsage 659 NetscapeServerGatedCryptoExtKeyUsage 660 MicrosoftCommercialCodeSigningExtKeyUsage 661 MicrosoftKernelCodeSigningExtKeyUsage 662) 663 664type CreationParameters struct { 665 Subject pkix.Name 666 DNSNames []string 667 EmailAddresses []string 668 IPAddresses []net.IP 669 URIs []*url.URL 670 OtherSANs map[string][]string 671 IsCA bool 672 KeyType string 673 KeyBits int 674 NotAfter time.Time 675 KeyUsage x509.KeyUsage 676 ExtKeyUsage CertExtKeyUsage 677 ExtKeyUsageOIDs []string 678 PolicyIdentifiers []string 679 BasicConstraintsValidForNonCA bool 680 681 // Only used when signing a CA cert 682 UseCSRValues bool 683 PermittedDNSDomains []string 684 685 // URLs to encode into the certificate 686 URLs *URLEntries 687 688 // The maximum path length to encode 689 MaxPathLength int 690 691 // The duration the certificate will use NotBefore 692 NotBeforeDuration time.Duration 693} 694 695type CreationBundle struct { 696 Params *CreationParameters 697 SigningBundle *CAInfoBundle 698 CSR *x509.CertificateRequest 699} 700 701// addKeyUsages adds appropriate key usages to the template given the creation 702// information 703func AddKeyUsages(data *CreationBundle, certTemplate *x509.Certificate) { 704 if data.Params.IsCA { 705 certTemplate.KeyUsage = x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign) 706 return 707 } 708 709 certTemplate.KeyUsage = data.Params.KeyUsage 710 711 if data.Params.ExtKeyUsage&AnyExtKeyUsage != 0 { 712 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageAny) 713 } 714 715 if data.Params.ExtKeyUsage&ServerAuthExtKeyUsage != 0 { 716 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageServerAuth) 717 } 718 719 if data.Params.ExtKeyUsage&ClientAuthExtKeyUsage != 0 { 720 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageClientAuth) 721 } 722 723 if data.Params.ExtKeyUsage&CodeSigningExtKeyUsage != 0 { 724 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageCodeSigning) 725 } 726 727 if data.Params.ExtKeyUsage&EmailProtectionExtKeyUsage != 0 { 728 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageEmailProtection) 729 } 730 731 if data.Params.ExtKeyUsage&IpsecEndSystemExtKeyUsage != 0 { 732 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageIPSECEndSystem) 733 } 734 735 if data.Params.ExtKeyUsage&IpsecTunnelExtKeyUsage != 0 { 736 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageIPSECTunnel) 737 } 738 739 if data.Params.ExtKeyUsage&IpsecUserExtKeyUsage != 0 { 740 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageIPSECUser) 741 } 742 743 if data.Params.ExtKeyUsage&TimeStampingExtKeyUsage != 0 { 744 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageTimeStamping) 745 } 746 747 if data.Params.ExtKeyUsage&OcspSigningExtKeyUsage != 0 { 748 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageOCSPSigning) 749 } 750 751 if data.Params.ExtKeyUsage&MicrosoftServerGatedCryptoExtKeyUsage != 0 { 752 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageMicrosoftServerGatedCrypto) 753 } 754 755 if data.Params.ExtKeyUsage&NetscapeServerGatedCryptoExtKeyUsage != 0 { 756 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageNetscapeServerGatedCrypto) 757 } 758 759 if data.Params.ExtKeyUsage&MicrosoftCommercialCodeSigningExtKeyUsage != 0 { 760 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageMicrosoftCommercialCodeSigning) 761 } 762 763 if data.Params.ExtKeyUsage&MicrosoftKernelCodeSigningExtKeyUsage != 0 { 764 certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageMicrosoftKernelCodeSigning) 765 } 766} 767