2015-06-05 18:03:57 +00:00
package pki
import (
2015-10-02 19:47:45 +00:00
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
2015-06-05 18:03:57 +00:00
"crypto/x509"
2015-10-02 19:47:45 +00:00
"crypto/x509/pkix"
2015-10-05 17:00:45 +00:00
"encoding/base64"
2015-06-05 18:03:57 +00:00
"encoding/pem"
"fmt"
"math"
2015-10-02 19:47:45 +00:00
mathrand "math/rand"
2015-10-14 15:46:01 +00:00
"net"
2015-06-05 18:03:57 +00:00
"os"
2015-10-14 15:46:01 +00:00
"reflect"
2016-02-22 16:21:28 +00:00
"strconv"
2015-10-02 19:47:45 +00:00
"strings"
2015-06-05 18:03:57 +00:00
"testing"
"time"
"github.com/fatih/structs"
2015-06-17 16:43:36 +00:00
"github.com/hashicorp/vault/helper/certutil"
2015-06-05 18:03:57 +00:00
"github.com/hashicorp/vault/logical"
logicaltest "github.com/hashicorp/vault/logical/testing"
"github.com/mitchellh/mapstructure"
)
var (
2016-06-22 20:08:24 +00:00
stepCount = 0
serialUnderTest string
parsedKeyUsageUnderTest int
2015-06-05 18:03:57 +00:00
)
2015-06-19 16:48:18 +00:00
// Performs basic tests on CA functionality
2015-10-05 17:00:45 +00:00
// Uses the RSA CA key
func TestBackend_RSAKey ( t * testing . T ) {
2015-09-01 12:56:31 +00:00
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
2015-08-27 19:24:37 +00:00
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
2015-09-01 22:29:30 +00:00
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
2015-08-27 19:24:37 +00:00
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
2015-06-05 18:03:57 +00:00
testCase := logicaltest . TestCase {
2016-07-01 21:27:35 +00:00
Backend : b ,
Steps : [ ] logicaltest . TestStep { } ,
2015-06-05 18:03:57 +00:00
}
2016-02-22 18:35:57 +00:00
stepCount = len ( testCase . Steps )
2015-06-05 18:03:57 +00:00
2015-10-03 01:02:16 +00:00
intdata := map [ string ] interface { } { }
reqdata := map [ string ] interface { } { }
2015-11-17 15:01:42 +00:00
testCase . Steps = append ( testCase . Steps , generateCATestingSteps ( t , rsaCACert , rsaCAKey , ecCACert , intdata , reqdata ) ... )
2015-06-05 18:03:57 +00:00
logicaltest . Test ( t , testCase )
}
2015-10-05 17:00:45 +00:00
// Performs basic tests on CA functionality
// Uses the EC CA key
func TestBackend_ECKey ( t * testing . T ) {
2015-09-01 12:56:31 +00:00
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
2015-08-27 19:24:37 +00:00
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
2015-09-01 22:29:30 +00:00
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
2015-08-27 19:24:37 +00:00
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
2015-06-05 18:03:57 +00:00
testCase := logicaltest . TestCase {
2016-07-01 21:27:35 +00:00
Backend : b ,
Steps : [ ] logicaltest . TestStep { } ,
2015-06-05 18:03:57 +00:00
}
2016-02-22 18:35:57 +00:00
stepCount = len ( testCase . Steps )
2015-10-05 17:00:45 +00:00
2015-10-03 01:02:16 +00:00
intdata := map [ string ] interface { } { }
reqdata := map [ string ] interface { } { }
2015-11-17 15:01:42 +00:00
testCase . Steps = append ( testCase . Steps , generateCATestingSteps ( t , ecCACert , ecCAKey , rsaCACert , intdata , reqdata ) ... )
2015-10-14 15:46:01 +00:00
logicaltest . Test ( t , testCase )
}
func TestBackend_CSRValues ( t * testing . T ) {
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2016-07-01 21:27:35 +00:00
Backend : b ,
Steps : [ ] logicaltest . TestStep { } ,
2015-10-14 15:46:01 +00:00
}
2016-02-22 18:35:57 +00:00
stepCount = len ( testCase . Steps )
2015-10-14 15:46:01 +00:00
intdata := map [ string ] interface { } { }
reqdata := map [ string ] interface { } { }
testCase . Steps = append ( testCase . Steps , generateCSRSteps ( t , ecCACert , ecCAKey , intdata , reqdata ) ... )
2015-10-05 17:00:45 +00:00
logicaltest . Test ( t , testCase )
}
2015-10-14 18:48:51 +00:00
func TestBackend_URLsCRUD ( t * testing . T ) {
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2016-07-01 21:27:35 +00:00
Backend : b ,
Steps : [ ] logicaltest . TestStep { } ,
2015-10-14 18:48:51 +00:00
}
2016-02-22 18:35:57 +00:00
stepCount = len ( testCase . Steps )
2015-10-14 18:48:51 +00:00
intdata := map [ string ] interface { } { }
reqdata := map [ string ] interface { } { }
testCase . Steps = append ( testCase . Steps , generateURLSteps ( t , ecCACert , ecCAKey , intdata , reqdata ) ... )
logicaltest . Test ( t , testCase )
}
2015-10-05 17:00:45 +00:00
// Generates and tests steps that walk through the various possibilities
// of role flags to ensure that they are properly restricted
// Uses the RSA CA key
func TestBackend_RSARoles ( t * testing . T ) {
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2016-07-01 21:27:35 +00:00
Backend : b ,
2015-10-05 17:00:45 +00:00
Steps : [ ] logicaltest . TestStep {
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-10-05 17:00:45 +00:00
Data : map [ string ] interface { } {
"pem_bundle" : rsaCAKey + rsaCACert ,
} ,
} ,
} ,
}
2016-02-22 18:35:57 +00:00
stepCount = len ( testCase . Steps )
2015-10-05 17:00:45 +00:00
testCase . Steps = append ( testCase . Steps , generateRoleSteps ( t , false ) ... )
2016-02-22 16:21:28 +00:00
if len ( os . Getenv ( "VAULT_VERBOSE_PKITESTS" ) ) > 0 {
for i , v := range testCase . Steps {
fmt . Printf ( "Step %d:\n%+v\n\n" , i + stepCount , v )
}
}
logicaltest . Test ( t , testCase )
}
// Generates and tests steps that walk through the various possibilities
// of role flags to ensure that they are properly restricted
// Uses the RSA CA key
func TestBackend_RSARoles_CSR ( t * testing . T ) {
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2016-07-01 21:27:35 +00:00
Backend : b ,
2016-02-22 16:21:28 +00:00
Steps : [ ] logicaltest . TestStep {
logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "config/ca" ,
Data : map [ string ] interface { } {
"pem_bundle" : rsaCAKey + rsaCACert ,
} ,
} ,
} ,
}
2016-02-22 18:35:57 +00:00
stepCount = len ( testCase . Steps )
2016-02-22 16:21:28 +00:00
testCase . Steps = append ( testCase . Steps , generateRoleSteps ( t , false ) ... )
2015-10-05 17:00:45 +00:00
if len ( os . Getenv ( "VAULT_VERBOSE_PKITESTS" ) ) > 0 {
for i , v := range testCase . Steps {
fmt . Printf ( "Step %d:\n%+v\n\n" , i + stepCount , v )
}
}
logicaltest . Test ( t , testCase )
}
// Generates and tests steps that walk through the various possibilities
// of role flags to ensure that they are properly restricted
// Uses the EC CA key
func TestBackend_ECRoles ( t * testing . T ) {
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2016-07-01 21:27:35 +00:00
Backend : b ,
2015-10-05 17:00:45 +00:00
Steps : [ ] logicaltest . TestStep {
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-10-05 17:00:45 +00:00
Data : map [ string ] interface { } {
"pem_bundle" : ecCAKey + ecCACert ,
} ,
} ,
} ,
}
2016-02-22 18:35:57 +00:00
stepCount = len ( testCase . Steps )
2015-10-02 19:47:45 +00:00
testCase . Steps = append ( testCase . Steps , generateRoleSteps ( t , false ) ... )
2016-02-22 16:21:28 +00:00
if len ( os . Getenv ( "VAULT_VERBOSE_PKITESTS" ) ) > 0 {
for i , v := range testCase . Steps {
fmt . Printf ( "Step %d:\n%+v\n\n" , i + stepCount , v )
}
}
logicaltest . Test ( t , testCase )
}
// Generates and tests steps that walk through the various possibilities
// of role flags to ensure that they are properly restricted
// Uses the EC CA key
func TestBackend_ECRoles_CSR ( t * testing . T ) {
defaultLeaseTTLVal := time . Hour * 24
maxLeaseTTLVal := time . Hour * 24 * 30
b , err := Factory ( & logical . BackendConfig {
Logger : nil ,
System : & logical . StaticSystemView {
DefaultLeaseTTLVal : defaultLeaseTTLVal ,
MaxLeaseTTLVal : maxLeaseTTLVal ,
} ,
} )
if err != nil {
t . Fatalf ( "Unable to create backend: %s" , err )
}
testCase := logicaltest . TestCase {
2016-07-01 21:27:35 +00:00
Backend : b ,
2016-02-22 16:21:28 +00:00
Steps : [ ] logicaltest . TestStep {
logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "config/ca" ,
Data : map [ string ] interface { } {
"pem_bundle" : ecCAKey + ecCACert ,
} ,
} ,
} ,
}
2016-02-22 18:35:57 +00:00
stepCount = len ( testCase . Steps )
2015-10-02 19:47:45 +00:00
testCase . Steps = append ( testCase . Steps , generateRoleSteps ( t , true ) ... )
2015-06-05 18:03:57 +00:00
if len ( os . Getenv ( "VAULT_VERBOSE_PKITESTS" ) ) > 0 {
for i , v := range testCase . Steps {
fmt . Printf ( "Step %d:\n%+v\n\n" , i + stepCount , v )
}
}
logicaltest . Test ( t , testCase )
}
2015-06-19 16:48:18 +00:00
// Performs some validity checking on the returned bundles
2016-06-22 20:08:24 +00:00
func checkCertsAndPrivateKey ( keyType string , key crypto . Signer , usage x509 . KeyUsage , extUsage x509 . ExtKeyUsage , validity time . Duration , certBundle * certutil . CertBundle ) ( * certutil . ParsedCertBundle , error ) {
2015-06-19 16:48:18 +00:00
parsedCertBundle , err := certBundle . ToParsedCertBundle ( )
if err != nil {
return nil , fmt . Errorf ( "Error parsing cert bundle: %s" , err )
}
2015-10-02 19:47:45 +00:00
if key != nil {
switch keyType {
case "rsa" :
parsedCertBundle . PrivateKeyType = certutil . RSAPrivateKey
parsedCertBundle . PrivateKey = key
parsedCertBundle . PrivateKeyBytes = x509 . MarshalPKCS1PrivateKey ( key . ( * rsa . PrivateKey ) )
case "ec" :
parsedCertBundle . PrivateKeyType = certutil . ECPrivateKey
parsedCertBundle . PrivateKey = key
parsedCertBundle . PrivateKeyBytes , err = x509 . MarshalECPrivateKey ( key . ( * ecdsa . PrivateKey ) )
if err != nil {
return nil , fmt . Errorf ( "Error parsing EC key: %s" , err )
}
}
}
2015-06-19 16:48:18 +00:00
switch {
case parsedCertBundle . Certificate == nil :
return nil , fmt . Errorf ( "Did not find a certificate in the cert bundle" )
case parsedCertBundle . IssuingCA == nil :
return nil , fmt . Errorf ( "Did not find a CA in the cert bundle" )
case parsedCertBundle . PrivateKey == nil :
return nil , fmt . Errorf ( "Did not find a private key in the cert bundle" )
case parsedCertBundle . PrivateKeyType == certutil . UnknownPrivateKey :
return nil , fmt . Errorf ( "Could not figure out type of private key" )
}
switch {
case parsedCertBundle . PrivateKeyType == certutil . RSAPrivateKey && keyType != "rsa" :
fallthrough
case parsedCertBundle . PrivateKeyType == certutil . ECPrivateKey && keyType != "ec" :
return nil , fmt . Errorf ( "Given key type does not match type found in bundle" )
}
cert := parsedCertBundle . Certificate
2016-06-22 20:08:24 +00:00
if usage != cert . KeyUsage {
return nil , fmt . Errorf ( "Expected usage of %#v, got %#v; ext usage is %#v" , usage , cert . KeyUsage , cert . ExtKeyUsage )
}
// There should only be one ext usage type, because only one is requested
2015-06-19 16:48:18 +00:00
// in the tests
if len ( cert . ExtKeyUsage ) != 1 {
2016-06-23 14:18:03 +00:00
return nil , fmt . Errorf ( "Got wrong size key usage in generated cert; expected 1, values are %#v" , cert . ExtKeyUsage )
2015-06-19 16:48:18 +00:00
}
2016-06-22 20:08:24 +00:00
switch extUsage {
case x509 . ExtKeyUsageEmailProtection :
2015-10-02 15:55:30 +00:00
if cert . ExtKeyUsage [ 0 ] != x509 . ExtKeyUsageEmailProtection {
2016-06-22 20:08:24 +00:00
return nil , fmt . Errorf ( "Bad extended key usage" )
2015-10-02 15:55:30 +00:00
}
2016-06-22 20:08:24 +00:00
case x509 . ExtKeyUsageServerAuth :
2015-06-19 16:48:18 +00:00
if cert . ExtKeyUsage [ 0 ] != x509 . ExtKeyUsageServerAuth {
2016-06-22 20:08:24 +00:00
return nil , fmt . Errorf ( "Bad extended key usage" )
2015-06-19 16:48:18 +00:00
}
2016-06-22 20:08:24 +00:00
case x509 . ExtKeyUsageClientAuth :
2015-06-19 16:48:18 +00:00
if cert . ExtKeyUsage [ 0 ] != x509 . ExtKeyUsageClientAuth {
2016-06-22 20:08:24 +00:00
return nil , fmt . Errorf ( "Bad extended key usage" )
2015-06-19 16:48:18 +00:00
}
2016-06-22 20:08:24 +00:00
case x509 . ExtKeyUsageCodeSigning :
2015-06-19 16:48:18 +00:00
if cert . ExtKeyUsage [ 0 ] != x509 . ExtKeyUsageCodeSigning {
2016-06-22 20:08:24 +00:00
return nil , fmt . Errorf ( "Bad extended key usage" )
2015-06-19 16:48:18 +00:00
}
}
2016-02-07 18:54:46 +00:00
// 40 seconds since we add 30 second slack for clock skew
if math . Abs ( float64 ( time . Now ( ) . Unix ( ) - cert . NotBefore . Unix ( ) ) ) > 40 {
2015-06-19 16:48:18 +00:00
return nil , fmt . Errorf ( "Validity period starts out of range" )
}
2016-02-07 18:54:46 +00:00
if ! cert . NotBefore . Before ( time . Now ( ) . Add ( - 10 * time . Second ) ) {
return nil , fmt . Errorf ( "Validity period not far enough in the past" )
}
2015-06-19 16:48:18 +00:00
if math . Abs ( float64 ( time . Now ( ) . Add ( validity ) . Unix ( ) - cert . NotAfter . Unix ( ) ) ) > 10 {
2015-08-27 19:24:37 +00:00
return nil , fmt . Errorf ( "Validity period of %d too large vs max of 10" , cert . NotAfter . Unix ( ) )
2015-06-19 16:48:18 +00:00
}
return parsedCertBundle , nil
}
2015-10-14 18:48:51 +00:00
func generateURLSteps ( t * testing . T , caCert , caKey string , intdata , reqdata map [ string ] interface { } ) [ ] logicaltest . TestStep {
expected := urlEntries {
IssuingCertificates : [ ] string {
"http://example.com/ca1" ,
"http://example.com/ca2" ,
} ,
CRLDistributionPoints : [ ] string {
"http://example.com/crl1" ,
"http://example.com/crl2" ,
} ,
OCSPServers : [ ] string {
"http://example.com/ocsp1" ,
"http://example.com/ocsp2" ,
} ,
}
csrTemplate := x509 . CertificateRequest {
Subject : pkix . Name {
CommonName : "my@example.com" ,
} ,
}
2016-02-18 22:55:47 +00:00
priv1024 , _ := rsa . GenerateKey ( rand . Reader , 1024 )
csr1024 , _ := x509 . CreateCertificateRequest ( rand . Reader , & csrTemplate , priv1024 )
csrPem1024 := pem . EncodeToMemory ( & pem . Block {
2015-10-14 18:48:51 +00:00
Type : "CERTIFICATE REQUEST" ,
2016-02-18 22:55:47 +00:00
Bytes : csr1024 ,
} )
priv2048 , _ := rsa . GenerateKey ( rand . Reader , 2048 )
csr2048 , _ := x509 . CreateCertificateRequest ( rand . Reader , & csrTemplate , priv2048 )
csrPem2048 := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE REQUEST" ,
Bytes : csr2048 ,
2015-10-14 18:48:51 +00:00
} )
ret := [ ] logicaltest . TestStep {
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/generate/exported" ,
2015-10-14 18:48:51 +00:00
Data : map [ string ] interface { } {
"common_name" : "Root Cert" ,
"ttl" : "180h" ,
} ,
2016-05-09 23:53:28 +00:00
Check : func ( resp * logical . Response ) error {
if resp . Secret != nil && resp . Secret . LeaseID != "" {
return fmt . Errorf ( "root returned with a lease" )
}
return nil
} ,
2015-10-14 18:48:51 +00:00
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-10-14 18:48:51 +00:00
Path : "config/urls" ,
Data : map [ string ] interface { } {
"issuing_certificates" : strings . Join ( expected . IssuingCertificates , "," ) ,
"crl_distribution_points" : strings . Join ( expected . CRLDistributionPoints , "," ) ,
"ocsp_servers" : strings . Join ( expected . OCSPServers , "," ) ,
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "config/urls" ,
Check : func ( resp * logical . Response ) error {
if resp . Data == nil {
return fmt . Errorf ( "no data returned" )
}
var entries urlEntries
err := mapstructure . Decode ( resp . Data , & entries )
if err != nil {
return err
}
if ! reflect . DeepEqual ( entries , expected ) {
return fmt . Errorf ( "expected urls\n%#v\ndoes not match provided\n%#v\n" , expected , entries )
}
return nil
} ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/sign-intermediate" ,
2015-10-14 18:48:51 +00:00
Data : map [ string ] interface { } {
2015-11-12 16:24:32 +00:00
"common_name" : "Intermediate Cert" ,
2016-02-18 22:55:47 +00:00
"csr" : string ( csrPem1024 ) ,
"format" : "der" ,
} ,
ErrorOk : true ,
Check : func ( resp * logical . Response ) error {
if ! resp . IsError ( ) {
return fmt . Errorf ( "expected an error response but did not get one" )
}
if ! strings . Contains ( resp . Data [ "error" ] . ( string ) , "2048" ) {
return fmt . Errorf ( "recieved an error but not about a 1024-bit key, error was: %s" , resp . Data [ "error" ] . ( string ) )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "root/sign-intermediate" ,
Data : map [ string ] interface { } {
"common_name" : "Intermediate Cert" ,
"csr" : string ( csrPem2048 ) ,
2015-11-12 16:24:32 +00:00
"format" : "der" ,
2015-10-14 18:48:51 +00:00
} ,
Check : func ( resp * logical . Response ) error {
certString := resp . Data [ "certificate" ] . ( string )
if certString == "" {
return fmt . Errorf ( "no certificate returned" )
}
2016-05-09 23:53:28 +00:00
if resp . Secret != nil && resp . Secret . LeaseID != "" {
return fmt . Errorf ( "signed intermediate returned with a lease" )
}
2015-10-14 18:48:51 +00:00
certBytes , _ := base64 . StdEncoding . DecodeString ( certString )
certs , err := x509 . ParseCertificates ( certBytes )
if err != nil {
return fmt . Errorf ( "returned cert cannot be parsed: %v" , err )
}
if len ( certs ) != 1 {
return fmt . Errorf ( "unexpected returned length of certificates: %d" , len ( certs ) )
}
cert := certs [ 0 ]
switch {
case ! reflect . DeepEqual ( expected . IssuingCertificates , cert . IssuingCertificateURL ) :
return fmt . Errorf ( "expected\n%#v\ngot\n%#v\n" , expected . IssuingCertificates , cert . IssuingCertificateURL )
case ! reflect . DeepEqual ( expected . CRLDistributionPoints , cert . CRLDistributionPoints ) :
return fmt . Errorf ( "expected\n%#v\ngot\n%#v\n" , expected . CRLDistributionPoints , cert . CRLDistributionPoints )
case ! reflect . DeepEqual ( expected . OCSPServers , cert . OCSPServer ) :
return fmt . Errorf ( "expected\n%#v\ngot\n%#v\n" , expected . OCSPServers , cert . OCSPServer )
2016-03-17 20:28:40 +00:00
case ! reflect . DeepEqual ( [ ] string { "Intermediate Cert" } , cert . DNSNames ) :
return fmt . Errorf ( "expected\n%#v\ngot\n%#v\n" , [ ] string { "Intermediate Cert" } , cert . DNSNames )
}
return nil
} ,
} ,
// Same as above but exclude adding to sans
logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "root/sign-intermediate" ,
Data : map [ string ] interface { } {
"common_name" : "Intermediate Cert" ,
"csr" : string ( csrPem2048 ) ,
"format" : "der" ,
"exclude_cn_from_sans" : true ,
} ,
Check : func ( resp * logical . Response ) error {
certString := resp . Data [ "certificate" ] . ( string )
if certString == "" {
return fmt . Errorf ( "no certificate returned" )
}
2016-05-09 23:53:28 +00:00
if resp . Secret != nil && resp . Secret . LeaseID != "" {
return fmt . Errorf ( "signed intermediate returned with a lease" )
}
2016-03-17 20:28:40 +00:00
certBytes , _ := base64 . StdEncoding . DecodeString ( certString )
certs , err := x509 . ParseCertificates ( certBytes )
if err != nil {
return fmt . Errorf ( "returned cert cannot be parsed: %v" , err )
}
if len ( certs ) != 1 {
return fmt . Errorf ( "unexpected returned length of certificates: %d" , len ( certs ) )
}
cert := certs [ 0 ]
switch {
case ! reflect . DeepEqual ( expected . IssuingCertificates , cert . IssuingCertificateURL ) :
return fmt . Errorf ( "expected\n%#v\ngot\n%#v\n" , expected . IssuingCertificates , cert . IssuingCertificateURL )
case ! reflect . DeepEqual ( expected . CRLDistributionPoints , cert . CRLDistributionPoints ) :
return fmt . Errorf ( "expected\n%#v\ngot\n%#v\n" , expected . CRLDistributionPoints , cert . CRLDistributionPoints )
case ! reflect . DeepEqual ( expected . OCSPServers , cert . OCSPServer ) :
return fmt . Errorf ( "expected\n%#v\ngot\n%#v\n" , expected . OCSPServers , cert . OCSPServer )
case ! reflect . DeepEqual ( [ ] string ( nil ) , cert . DNSNames ) :
return fmt . Errorf ( "expected\n%#v\ngot\n%#v\n" , [ ] string ( nil ) , cert . DNSNames )
2015-10-14 18:48:51 +00:00
}
2016-02-18 22:55:47 +00:00
2015-10-14 18:48:51 +00:00
return nil
} ,
} ,
}
return ret
}
2015-10-14 15:46:01 +00:00
func generateCSRSteps ( t * testing . T , caCert , caKey string , intdata , reqdata map [ string ] interface { } ) [ ] logicaltest . TestStep {
csrTemplate := x509 . CertificateRequest {
Subject : pkix . Name {
Country : [ ] string { "MyCountry" } ,
PostalCode : [ ] string { "MyPostalCode" } ,
SerialNumber : "MySerialNumber" ,
CommonName : "my@example.com" ,
} ,
DNSNames : [ ] string {
"name1.example.com" ,
"name2.example.com" ,
"name3.example.com" ,
} ,
EmailAddresses : [ ] string {
"name1@example.com" ,
"name2@example.com" ,
"name3@example.com" ,
} ,
IPAddresses : [ ] net . IP {
net . ParseIP ( "::ff:1:2:3:4" ) ,
net . ParseIP ( "::ff:5:6:7:8" ) ,
} ,
}
priv , _ := rsa . GenerateKey ( rand . Reader , 2048 )
csr , _ := x509 . CreateCertificateRequest ( rand . Reader , & csrTemplate , priv )
csrPem := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE REQUEST" ,
Bytes : csr ,
} )
ret := [ ] logicaltest . TestStep {
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/generate/exported" ,
2015-10-14 15:46:01 +00:00
Data : map [ string ] interface { } {
2015-11-12 16:24:32 +00:00
"common_name" : "Root Cert" ,
"ttl" : "180h" ,
"max_path_length" : 0 ,
} ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/sign-intermediate" ,
2015-11-12 16:24:32 +00:00
Data : map [ string ] interface { } {
"use_csr_values" : true ,
"csr" : string ( csrPem ) ,
"format" : "der" ,
} ,
ErrorOk : true ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/generate/exported" ,
2015-11-12 16:24:32 +00:00
Data : map [ string ] interface { } {
"common_name" : "Root Cert" ,
"ttl" : "180h" ,
"max_path_length" : 1 ,
2015-10-14 15:46:01 +00:00
} ,
} ,
2015-11-17 15:01:42 +00:00
2015-10-14 15:46:01 +00:00
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/sign-intermediate" ,
2015-10-14 15:46:01 +00:00
Data : map [ string ] interface { } {
"use_csr_values" : true ,
"csr" : string ( csrPem ) ,
"format" : "der" ,
} ,
Check : func ( resp * logical . Response ) error {
certString := resp . Data [ "certificate" ] . ( string )
if certString == "" {
return fmt . Errorf ( "no certificate returned" )
}
certBytes , _ := base64 . StdEncoding . DecodeString ( certString )
certs , err := x509 . ParseCertificates ( certBytes )
if err != nil {
return fmt . Errorf ( "returned cert cannot be parsed: %v" , err )
}
if len ( certs ) != 1 {
return fmt . Errorf ( "unexpected returned length of certificates: %d" , len ( certs ) )
}
cert := certs [ 0 ]
2015-11-12 16:24:32 +00:00
if cert . MaxPathLen != 0 {
return fmt . Errorf ( "max path length of %d does not match the requested of 3" , cert . MaxPathLen )
}
if ! cert . MaxPathLenZero {
return fmt . Errorf ( "max path length zero is not set" )
}
2015-10-14 15:46:01 +00:00
// We need to set these as they are filled in with unparsed values in the final cert
csrTemplate . Subject . Names = cert . Subject . Names
csrTemplate . Subject . ExtraNames = cert . Subject . ExtraNames
2015-11-12 16:24:32 +00:00
2015-10-14 15:46:01 +00:00
switch {
case ! reflect . DeepEqual ( cert . Subject , csrTemplate . Subject ) :
return fmt . Errorf ( "cert subject\n%#v\ndoes not match csr subject\n%#v\n" , cert . Subject , csrTemplate . Subject )
case ! reflect . DeepEqual ( cert . DNSNames , csrTemplate . DNSNames ) :
return fmt . Errorf ( "cert dns names\n%#v\ndoes not match csr dns names\n%#v\n" , cert . DNSNames , csrTemplate . DNSNames )
case ! reflect . DeepEqual ( cert . EmailAddresses , csrTemplate . EmailAddresses ) :
return fmt . Errorf ( "cert email addresses\n%#v\ndoes not match csr email addresses\n%#v\n" , cert . EmailAddresses , csrTemplate . EmailAddresses )
case ! reflect . DeepEqual ( cert . IPAddresses , csrTemplate . IPAddresses ) :
return fmt . Errorf ( "cert ip addresses\n%#v\ndoes not match csr ip addresses\n%#v\n" , cert . IPAddresses , csrTemplate . IPAddresses )
}
return nil
} ,
} ,
}
return ret
}
2015-06-19 16:48:18 +00:00
// Generates steps to test out CA configuration -- certificates + CRL expiry,
// and ensure that the certificates are readable after storing them
2015-11-17 15:01:42 +00:00
func generateCATestingSteps ( t * testing . T , caCert , caKey , otherCaCert string , intdata , reqdata map [ string ] interface { } ) [ ] logicaltest . TestStep {
2016-02-24 21:19:01 +00:00
setSerialUnderTest := func ( req * logical . Request ) error {
req . Path = serialUnderTest
return nil
}
2015-06-05 18:03:57 +00:00
ret := [ ] logicaltest . TestStep {
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-06-05 18:03:57 +00:00
Data : map [ string ] interface { } {
"pem_bundle" : caKey + caCert ,
} ,
} ,
2015-06-19 16:48:18 +00:00
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-06-19 16:48:18 +00:00
Path : "config/crl" ,
Data : map [ string ] interface { } {
"expiry" : "16h" ,
} ,
} ,
2015-06-05 18:03:57 +00:00
// Ensure we can fetch it back via unauthenticated means, in various formats
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "cert/ca" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "certificate" ] . ( string ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , resp . Data [ "certificate" ] . ( string ) , caCert )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "ca/pem" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
rawBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
if string ( rawBytes ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , string ( rawBytes ) , caCert )
}
if resp . Data [ "http_content_type" ] . ( string ) != "application/pkix-cert" {
return fmt . Errorf ( "Expected application/pkix-cert as content-type, but got %s" , resp . Data [ "http_content_type" ] . ( string ) )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "ca" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
rawBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
pemBytes := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE" ,
Bytes : rawBytes ,
} )
if string ( pemBytes ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , string ( pemBytes ) , caCert )
}
if resp . Data [ "http_content_type" ] . ( string ) != "application/pkix-cert" {
return fmt . Errorf ( "Expected application/pkix-cert as content-type, but got %s" , resp . Data [ "http_content_type" ] . ( string ) )
}
return nil
} ,
} ,
2015-06-19 16:48:18 +00:00
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "config/crl" ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "expiry" ] . ( string ) != "16h" {
return fmt . Errorf ( "CRL lifetimes do not match (got %s)" , resp . Data [ "expiry" ] . ( string ) )
}
return nil
} ,
} ,
2015-08-29 13:03:02 +00:00
2015-11-18 15:16:09 +00:00
// Ensure that both parts of the PEM bundle are required
// Here, just the cert
2015-11-17 15:01:42 +00:00
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-11-17 15:01:42 +00:00
Data : map [ string ] interface { } {
2015-11-18 15:16:09 +00:00
"pem_bundle" : caCert ,
2015-11-17 15:01:42 +00:00
} ,
ErrorOk : true ,
} ,
2015-11-18 15:16:09 +00:00
// Here, just the key
2015-08-29 13:03:02 +00:00
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-08-29 13:03:02 +00:00
Data : map [ string ] interface { } {
2015-11-18 15:16:09 +00:00
"pem_bundle" : caKey ,
2015-08-29 13:03:02 +00:00
} ,
2015-11-18 15:16:09 +00:00
ErrorOk : true ,
2015-08-29 13:03:02 +00:00
} ,
// Ensure we can fetch it back via unauthenticated means, in various formats
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "cert/ca" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "certificate" ] . ( string ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , resp . Data [ "certificate" ] . ( string ) , caCert )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "ca/pem" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
rawBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
if string ( rawBytes ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , string ( rawBytes ) , caCert )
}
if resp . Data [ "http_content_type" ] . ( string ) != "application/pkix-cert" {
return fmt . Errorf ( "Expected application/pkix-cert as content-type, but got %s" , resp . Data [ "http_content_type" ] . ( string ) )
}
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "ca" ,
Unauthenticated : true ,
Check : func ( resp * logical . Response ) error {
rawBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
pemBytes := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE" ,
Bytes : rawBytes ,
} )
if string ( pemBytes ) != caCert {
return fmt . Errorf ( "CA certificate:\n%s\ndoes not match original:\n%s\n" , string ( pemBytes ) , caCert )
}
if resp . Data [ "http_content_type" ] . ( string ) != "application/pkix-cert" {
return fmt . Errorf ( "Expected application/pkix-cert as content-type, but got %s" , resp . Data [ "http_content_type" ] . ( string ) )
}
return nil
} ,
} ,
2015-10-03 01:02:16 +00:00
2015-10-05 17:00:45 +00:00
// Test a bunch of generation stuff
2015-10-03 01:02:16 +00:00
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/generate/exported" ,
2015-10-03 01:02:16 +00:00
Data : map [ string ] interface { } {
"common_name" : "Root Cert" ,
"ttl" : "180h" ,
} ,
Check : func ( resp * logical . Response ) error {
intdata [ "root" ] = resp . Data [ "certificate" ] . ( string )
intdata [ "rootkey" ] = resp . Data [ "private_key" ] . ( string )
reqdata [ "pem_bundle" ] = intdata [ "root" ] . ( string ) + "\n" + intdata [ "rootkey" ] . ( string )
return nil
} ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "intermediate/generate/exported" ,
2015-11-12 16:24:32 +00:00
Data : map [ string ] interface { } {
"common_name" : "Intermediate Cert" ,
} ,
2015-10-03 01:02:16 +00:00
Check : func ( resp * logical . Response ) error {
intdata [ "intermediatecsr" ] = resp . Data [ "csr" ] . ( string )
intdata [ "intermediatekey" ] = resp . Data [ "private_key" ] . ( string )
return nil
} ,
} ,
2015-11-18 15:16:09 +00:00
// Re-load the root key in so we can sign it
2015-10-03 01:02:16 +00:00
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-10-03 01:02:16 +00:00
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
delete ( reqdata , "pem_bundle" )
delete ( reqdata , "ttl" )
reqdata [ "csr" ] = intdata [ "intermediatecsr" ] . ( string )
reqdata [ "common_name" ] = "Intermediate Cert"
2016-02-24 21:19:01 +00:00
reqdata [ "ttl" ] = "10s"
2015-10-03 01:02:16 +00:00
return nil
} ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/sign-intermediate" ,
2015-10-03 01:02:16 +00:00
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
delete ( reqdata , "csr" )
delete ( reqdata , "common_name" )
delete ( reqdata , "ttl" )
2015-11-18 15:16:09 +00:00
intdata [ "intermediatecert" ] = resp . Data [ "certificate" ] . ( string )
2015-10-03 01:02:16 +00:00
reqdata [ "serial_number" ] = resp . Data [ "serial_number" ] . ( string )
2016-02-24 21:19:01 +00:00
reqdata [ "rsa_int_serial_number" ] = resp . Data [ "serial_number" ] . ( string )
2015-11-18 15:16:09 +00:00
reqdata [ "certificate" ] = resp . Data [ "certificate" ] . ( string )
reqdata [ "pem_bundle" ] = intdata [ "intermediatekey" ] . ( string ) + "\n" + resp . Data [ "certificate" ] . ( string )
return nil
} ,
} ,
// First load in this way to populate the private key
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-11-18 15:16:09 +00:00
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
delete ( reqdata , "pem_bundle" )
return nil
} ,
} ,
// Now test setting the intermediate, signed CA cert
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "intermediate/set-signed" ,
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
delete ( reqdata , "certificate" )
2016-03-07 15:57:38 +00:00
serialUnderTest = "cert/" + reqdata [ "rsa_int_serial_number" ] . ( string )
return nil
} ,
} ,
// We expect to find a zero revocation time
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != nil && resp . Data [ "error" ] . ( string ) != "" {
return fmt . Errorf ( "got an error: %s" , resp . Data [ "error" ] . ( string ) )
}
if resp . Data [ "revocation_time" ] . ( int64 ) != 0 {
return fmt . Errorf ( "expected a zero revocation time" )
}
2015-10-03 01:02:16 +00:00
return nil
} ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-10-03 01:02:16 +00:00
Path : "revoke" ,
Data : reqdata ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "crl" ,
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
crlBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
certList , err := x509 . ParseCRL ( crlBytes )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
revokedList := certList . TBSCertList . RevokedCertificates
if len ( revokedList ) != 1 {
t . Fatalf ( "length of revoked list not 1; %d" , len ( revokedList ) )
}
revokedString := certutil . GetOctalFormatted ( revokedList [ 0 ] . SerialNumber . Bytes ( ) , ":" )
if revokedString != reqdata [ "serial_number" ] . ( string ) {
t . Fatalf ( "got serial %s, expecting %s" , revokedString , reqdata [ "serial_number" ] . ( string ) )
}
2015-10-05 17:00:45 +00:00
delete ( reqdata , "serial_number" )
return nil
} ,
} ,
// Do it all again, with EC keys and DER format
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/generate/exported" ,
2015-10-05 17:00:45 +00:00
Data : map [ string ] interface { } {
"common_name" : "Root Cert" ,
"ttl" : "180h" ,
"key_type" : "ec" ,
"key_bits" : 384 ,
"format" : "der" ,
} ,
Check : func ( resp * logical . Response ) error {
certBytes , _ := base64 . StdEncoding . DecodeString ( resp . Data [ "certificate" ] . ( string ) )
certPem := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE" ,
Bytes : certBytes ,
} )
keyBytes , _ := base64 . StdEncoding . DecodeString ( resp . Data [ "private_key" ] . ( string ) )
keyPem := pem . EncodeToMemory ( & pem . Block {
Type : "EC PRIVATE KEY" ,
Bytes : keyBytes ,
} )
intdata [ "root" ] = string ( certPem )
intdata [ "rootkey" ] = string ( keyPem )
reqdata [ "pem_bundle" ] = string ( certPem ) + "\n" + string ( keyPem )
return nil
} ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "intermediate/generate/exported" ,
2015-10-05 17:00:45 +00:00
Data : map [ string ] interface { } {
2015-11-12 16:24:32 +00:00
"format" : "der" ,
"key_type" : "ec" ,
"key_bits" : 384 ,
"common_name" : "Intermediate Cert" ,
2015-10-05 17:00:45 +00:00
} ,
Check : func ( resp * logical . Response ) error {
csrBytes , _ := base64 . StdEncoding . DecodeString ( resp . Data [ "csr" ] . ( string ) )
csrPem := pem . EncodeToMemory ( & pem . Block {
Type : "CERTIFICATE REQUEST" ,
Bytes : csrBytes ,
} )
keyBytes , _ := base64 . StdEncoding . DecodeString ( resp . Data [ "private_key" ] . ( string ) )
keyPem := pem . EncodeToMemory ( & pem . Block {
Type : "EC PRIVATE KEY" ,
Bytes : keyBytes ,
} )
intdata [ "intermediatecsr" ] = string ( csrPem )
intdata [ "intermediatekey" ] = string ( keyPem )
return nil
} ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-10-05 17:00:45 +00:00
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
delete ( reqdata , "pem_bundle" )
delete ( reqdata , "ttl" )
reqdata [ "csr" ] = intdata [ "intermediatecsr" ] . ( string )
reqdata [ "common_name" ] = "Intermediate Cert"
2016-02-24 21:19:01 +00:00
reqdata [ "ttl" ] = "10s"
2015-10-05 17:00:45 +00:00
return nil
} ,
} ,
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "root/sign-intermediate" ,
2015-10-05 17:00:45 +00:00
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
delete ( reqdata , "csr" )
delete ( reqdata , "common_name" )
delete ( reqdata , "ttl" )
2015-11-18 15:16:09 +00:00
intdata [ "intermediatecert" ] = resp . Data [ "certificate" ] . ( string )
2015-10-05 17:00:45 +00:00
reqdata [ "serial_number" ] = resp . Data [ "serial_number" ] . ( string )
2016-02-24 21:19:01 +00:00
reqdata [ "ec_int_serial_number" ] = resp . Data [ "serial_number" ] . ( string )
2015-11-18 15:16:09 +00:00
reqdata [ "certificate" ] = resp . Data [ "certificate" ] . ( string )
reqdata [ "pem_bundle" ] = intdata [ "intermediatekey" ] . ( string ) + "\n" + resp . Data [ "certificate" ] . ( string )
return nil
} ,
} ,
// First load in this way to populate the private key
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-19 15:13:28 +00:00
Path : "config/ca" ,
2015-11-18 15:16:09 +00:00
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
delete ( reqdata , "pem_bundle" )
return nil
} ,
} ,
// Now test setting the intermediate, signed CA cert
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-11-18 15:16:09 +00:00
Path : "intermediate/set-signed" ,
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
delete ( reqdata , "certificate" )
2016-03-07 15:57:38 +00:00
serialUnderTest = "cert/" + reqdata [ "ec_int_serial_number" ] . ( string )
2015-10-05 17:00:45 +00:00
return nil
} ,
} ,
2016-03-07 15:57:38 +00:00
// We expect to find a zero revocation time
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != nil && resp . Data [ "error" ] . ( string ) != "" {
return fmt . Errorf ( "got an error: %s" , resp . Data [ "error" ] . ( string ) )
}
if resp . Data [ "revocation_time" ] . ( int64 ) != 0 {
return fmt . Errorf ( "expected a zero revocation time" )
}
return nil
} ,
} ,
2015-10-05 17:00:45 +00:00
logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-10-05 17:00:45 +00:00
Path : "revoke" ,
Data : reqdata ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "crl" ,
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
crlBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
certList , err := x509 . ParseCRL ( crlBytes )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
revokedList := certList . TBSCertList . RevokedCertificates
if len ( revokedList ) != 2 {
t . Fatalf ( "length of revoked list not 2; %d" , len ( revokedList ) )
}
found := false
for _ , revEntry := range revokedList {
revokedString := certutil . GetOctalFormatted ( revEntry . SerialNumber . Bytes ( ) , ":" )
if revokedString == reqdata [ "serial_number" ] . ( string ) {
found = true
}
}
if ! found {
t . Fatalf ( "did not find %s in CRL" , reqdata [ "serial_number" ] . ( string ) )
}
delete ( reqdata , "serial_number" )
2016-02-24 21:19:01 +00:00
serialUnderTest = "cert/" + reqdata [ "rsa_int_serial_number" ] . ( string )
return nil
} ,
} ,
// Make sure both serial numbers we expect to find are found
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != nil && resp . Data [ "error" ] . ( string ) != "" {
return fmt . Errorf ( "got an error: %s" , resp . Data [ "error" ] . ( string ) )
}
2016-03-07 15:57:38 +00:00
if resp . Data [ "revocation_time" ] . ( int64 ) == 0 {
return fmt . Errorf ( "expected a non-zero revocation time" )
}
2016-02-24 21:19:01 +00:00
serialUnderTest = "cert/" + reqdata [ "ec_int_serial_number" ] . ( string )
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != nil && resp . Data [ "error" ] . ( string ) != "" {
return fmt . Errorf ( "got an error: %s" , resp . Data [ "error" ] . ( string ) )
}
2016-03-07 15:57:38 +00:00
if resp . Data [ "revocation_time" ] . ( int64 ) == 0 {
return fmt . Errorf ( "expected a non-zero revocation time" )
}
2016-02-24 21:19:01 +00:00
// Give time for the certificates to pass the safety buffer
t . Logf ( "Sleeping for 15 seconds to allow safety buffer time to pass before testing tidying" )
time . Sleep ( 15 * time . Second )
serialUnderTest = "cert/" + reqdata [ "rsa_int_serial_number" ] . ( string )
return nil
} ,
} ,
// This shouldn't do anything since the safety buffer is too long
logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "tidy" ,
Data : map [ string ] interface { } {
"safety_buffer" : "3h" ,
"tidy_cert_store" : true ,
"tidy_revocation_list" : true ,
} ,
} ,
// We still expect to find these
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != nil && resp . Data [ "error" ] . ( string ) != "" {
return fmt . Errorf ( "got an error: %s" , resp . Data [ "error" ] . ( string ) )
}
serialUnderTest = "cert/" + reqdata [ "ec_int_serial_number" ] . ( string )
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != nil && resp . Data [ "error" ] . ( string ) != "" {
return fmt . Errorf ( "got an error: %s" , resp . Data [ "error" ] . ( string ) )
}
serialUnderTest = "cert/" + reqdata [ "rsa_int_serial_number" ] . ( string )
return nil
} ,
} ,
// Both should appear in the CRL
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "crl" ,
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
crlBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
certList , err := x509 . ParseCRL ( crlBytes )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
revokedList := certList . TBSCertList . RevokedCertificates
if len ( revokedList ) != 2 {
t . Fatalf ( "length of revoked list not 2; %d" , len ( revokedList ) )
}
foundRsa := false
foundEc := false
for _ , revEntry := range revokedList {
revokedString := certutil . GetOctalFormatted ( revEntry . SerialNumber . Bytes ( ) , ":" )
if revokedString == reqdata [ "rsa_int_serial_number" ] . ( string ) {
foundRsa = true
}
if revokedString == reqdata [ "ec_int_serial_number" ] . ( string ) {
foundEc = true
}
}
if ! foundRsa || ! foundEc {
t . Fatalf ( "did not find an expected entry in CRL" )
}
return nil
} ,
} ,
// This shouldn't do anything since the boolean values default to false
logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "tidy" ,
Data : map [ string ] interface { } {
"safety_buffer" : "1s" ,
} ,
} ,
// We still expect to find these
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != nil && resp . Data [ "error" ] . ( string ) != "" {
return fmt . Errorf ( "got an error: %s" , resp . Data [ "error" ] . ( string ) )
}
serialUnderTest = "cert/" + reqdata [ "ec_int_serial_number" ] . ( string )
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] != nil && resp . Data [ "error" ] . ( string ) != "" {
return fmt . Errorf ( "got an error: %s" , resp . Data [ "error" ] . ( string ) )
}
serialUnderTest = "cert/" + reqdata [ "rsa_int_serial_number" ] . ( string )
return nil
} ,
} ,
// This should remove the values since the safety buffer is short
logicaltest . TestStep {
Operation : logical . UpdateOperation ,
Path : "tidy" ,
Data : map [ string ] interface { } {
"safety_buffer" : "1s" ,
"tidy_cert_store" : true ,
"tidy_revocation_list" : true ,
} ,
} ,
// We do *not* expect to find these
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] == nil || resp . Data [ "error" ] . ( string ) == "" {
return fmt . Errorf ( "didn't get an expected error" )
}
serialUnderTest = "cert/" + reqdata [ "ec_int_serial_number" ] . ( string )
return nil
} ,
} ,
logicaltest . TestStep {
Operation : logical . ReadOperation ,
PreFlight : setSerialUnderTest ,
Check : func ( resp * logical . Response ) error {
if resp . Data [ "error" ] == nil || resp . Data [ "error" ] . ( string ) == "" {
return fmt . Errorf ( "didn't get an expected error" )
}
serialUnderTest = "cert/" + reqdata [ "rsa_int_serial_number" ] . ( string )
return nil
} ,
} ,
// Both should be gone from the CRL
logicaltest . TestStep {
Operation : logical . ReadOperation ,
Path : "crl" ,
Data : reqdata ,
Check : func ( resp * logical . Response ) error {
crlBytes := resp . Data [ "http_raw_body" ] . ( [ ] byte )
certList , err := x509 . ParseCRL ( crlBytes )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
revokedList := certList . TBSCertList . RevokedCertificates
if len ( revokedList ) != 0 {
t . Fatalf ( "length of revoked list not 0; %d" , len ( revokedList ) )
}
2015-10-03 01:02:16 +00:00
return nil
} ,
} ,
2015-06-05 18:03:57 +00:00
}
return ret
}
2015-06-19 16:48:18 +00:00
// Generates steps to test out various role permutations
2015-10-02 19:47:45 +00:00
func generateRoleSteps ( t * testing . T , useCSRs bool ) [ ] logicaltest . TestStep {
2015-06-05 18:03:57 +00:00
roleVals := roleEntry {
2015-10-05 17:00:45 +00:00
MaxTTL : "12h" ,
KeyType : "rsa" ,
KeyBits : 2048 ,
2015-06-05 18:03:57 +00:00
}
2015-06-15 17:33:23 +00:00
issueVals := certutil . IssueData { }
2015-06-05 18:03:57 +00:00
ret := [ ] logicaltest . TestStep { }
roleTestStep := logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-06-05 18:03:57 +00:00
Path : "roles/test" ,
}
2015-10-02 19:47:45 +00:00
var issueTestStep logicaltest . TestStep
if useCSRs {
issueTestStep = logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-10-02 19:47:45 +00:00
Path : "sign/test" ,
}
} else {
issueTestStep = logicaltest . TestStep {
2016-01-07 15:30:47 +00:00
Operation : logical . UpdateOperation ,
2015-10-02 19:47:45 +00:00
Path : "issue/test" ,
}
2015-06-05 18:03:57 +00:00
}
2016-07-01 21:27:35 +00:00
generatedRSAKeys := map [ int ] crypto . Signer { }
generatedECKeys := map [ int ] crypto . Signer { }
2016-02-22 16:21:28 +00:00
/ *
// For the number of tests being run, a seed of 1 has been tested
// to hit all of the various values below. However, for normal
// testing we use a randomized time for maximum fuzziness.
* /
var seed int64 = 1
fixedSeed := os . Getenv ( "VAULT_PKITESTS_FIXED_SEED" )
if len ( fixedSeed ) == 0 {
seed = time . Now ( ) . UnixNano ( )
} else {
var err error
seed , err = strconv . ParseInt ( fixedSeed , 10 , 64 )
if err != nil {
t . Fatalf ( "error parsing fixed seed of %s: %v" , fixedSeed , err )
}
}
mathRand := mathrand . New ( mathrand . NewSource ( seed ) )
t . Logf ( "seed under test: %v" , seed )
2016-02-22 18:35:57 +00:00
// Used by tests not toggling common names to turn off the behavior of random key bit fuzziness
keybitSizeRandOff := false
2015-06-05 18:03:57 +00:00
genericErrorOkCheck := func ( resp * logical . Response ) error {
if resp . IsError ( ) {
return nil
}
return fmt . Errorf ( "Expected an error, but did not seem to get one" )
}
2015-06-19 16:48:18 +00:00
// Adds tests with the currently configured issue/role information
2015-06-05 18:03:57 +00:00
addTests := func ( testCheck logicaltest . TestCheckFunc ) {
2016-02-22 18:35:57 +00:00
stepCount += 1
//t.Logf("test step %d\nrole vals: %#v\n", stepCount, roleVals)
stepCount += 1
//t.Logf("test step %d\nissue vals: %#v\n", stepCount, issueTestStep)
2015-06-05 18:03:57 +00:00
roleTestStep . Data = structs . New ( roleVals ) . Map ( )
ret = append ( ret , roleTestStep )
issueTestStep . Data = structs . New ( issueVals ) . Map ( )
switch {
case issueTestStep . ErrorOk :
issueTestStep . Check = genericErrorOkCheck
case testCheck != nil :
issueTestStep . Check = testCheck
default :
issueTestStep . Check = nil
}
ret = append ( ret , issueTestStep )
}
2015-06-19 16:48:18 +00:00
// Returns a TestCheckFunc that performs various validity checks on the
// returned certificate information, mostly within checkCertsAndPrivateKey
2016-06-22 20:08:24 +00:00
getCnCheck := func ( name string , role roleEntry , key crypto . Signer , usage x509 . KeyUsage , extUsage x509 . ExtKeyUsage , validity time . Duration ) logicaltest . TestCheckFunc {
2015-06-15 17:33:23 +00:00
var certBundle certutil . CertBundle
2015-06-05 18:03:57 +00:00
return func ( resp * logical . Response ) error {
2015-06-15 17:33:23 +00:00
err := mapstructure . Decode ( resp . Data , & certBundle )
2015-06-05 18:03:57 +00:00
if err != nil {
return err
}
2016-06-22 20:08:24 +00:00
parsedCertBundle , err := checkCertsAndPrivateKey ( role . KeyType , key , usage , extUsage , validity , & certBundle )
2015-06-05 18:03:57 +00:00
if err != nil {
return fmt . Errorf ( "Error checking generated certificate: %s" , err )
}
2015-06-19 16:48:18 +00:00
cert := parsedCertBundle . Certificate
2015-06-05 18:03:57 +00:00
if cert . Subject . CommonName != name {
return fmt . Errorf ( "Error: returned certificate has CN of %s but %s was requested" , cert . Subject . CommonName , name )
}
2015-10-03 01:02:16 +00:00
if strings . Contains ( cert . Subject . CommonName , "@" ) {
if len ( cert . DNSNames ) != 0 || len ( cert . EmailAddresses ) != 1 {
return fmt . Errorf ( "Error: found more than one DNS SAN or not one Email SAN but only one was requested, cert.DNSNames = %#v, cert.EmailAddresses = %#v" , cert . DNSNames , cert . EmailAddresses )
}
} else {
if len ( cert . DNSNames ) != 1 || len ( cert . EmailAddresses ) != 0 {
return fmt . Errorf ( "Error: found more than one Email SAN or not one DNS SAN but only one was requested, cert.DNSNames = %#v, cert.EmailAddresses = %#v" , cert . DNSNames , cert . EmailAddresses )
}
2015-06-05 18:03:57 +00:00
}
2015-10-02 18:27:30 +00:00
var retName string
if len ( cert . DNSNames ) > 0 {
retName = cert . DNSNames [ 0 ]
}
if len ( cert . EmailAddresses ) > 0 {
retName = cert . EmailAddresses [ 0 ]
}
if retName != name {
return fmt . Errorf ( "Error: returned certificate has a DNS SAN of %s but %s was requested" , retName , name )
2015-06-05 18:03:57 +00:00
}
return nil
}
}
2015-06-19 16:48:18 +00:00
// Common names to test with the various role flags toggled
2015-06-05 18:03:57 +00:00
var commonNames struct {
2015-10-02 16:22:02 +00:00
Localhost bool ` structs:"localhost" `
2015-12-01 04:49:11 +00:00
BareDomain bool ` structs:"example.com" `
SecondDomain bool ` structs:"foobar.com" `
2015-10-02 16:22:02 +00:00
SubDomain bool ` structs:"foo.example.com" `
Wildcard bool ` structs:"*.example.com" `
SubSubdomain bool ` structs:"foo.bar.example.com" `
SubSubdomainWildcard bool ` structs:"*.bar.example.com" `
NonHostname bool ` structs:"daɪ ˈ ɛrɨsɨs" `
AnyHost bool ` structs:"porkslap.beer" `
2015-06-05 18:03:57 +00:00
}
2015-06-19 16:48:18 +00:00
// Adds a series of tests based on the current selection of
// allowed common names; contains some (seeded) randomness
//
// This allows for a variety of common names to be tested in various
// combinations with allowed toggles of the role
2015-06-05 18:03:57 +00:00
addCnTests := func ( ) {
cnMap := structs . New ( commonNames ) . Map ( )
for name , allowedInt := range cnMap {
roleVals . KeyType = "rsa"
roleVals . KeyBits = 2048
if mathRand . Int ( ) % 2 == 1 {
roleVals . KeyType = "ec"
roleVals . KeyBits = 224
}
roleVals . ServerFlag = false
roleVals . ClientFlag = false
roleVals . CodeSigningFlag = false
2015-10-02 15:55:30 +00:00
roleVals . EmailProtectionFlag = false
2016-06-22 20:08:24 +00:00
var usage string
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",DigitalSignature"
}
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",ContentCoMmitment"
}
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",KeyEncipherment"
}
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",DataEncipherment"
}
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",KeyAgreemEnt"
}
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",CertSign"
}
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",CRLSign"
}
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",EncipherOnly"
}
if mathRand . Int ( ) % 2 == 1 {
usage = usage + ",DecipherOnly"
}
roleVals . KeyUsage = usage
parsedKeyUsage := parseKeyUsages ( roleVals . KeyUsage )
2016-06-23 13:49:03 +00:00
if parsedKeyUsage == 0 && usage != "" {
panic ( "parsed key usages was zero" )
}
2016-06-22 20:08:24 +00:00
parsedKeyUsageUnderTest = parsedKeyUsage
var extUsage x509 . ExtKeyUsage
i := mathRand . Int ( ) % 4
2015-06-05 18:03:57 +00:00
switch {
2016-06-22 20:08:24 +00:00
case i == 0 :
extUsage = x509 . ExtKeyUsageEmailProtection
2015-10-02 15:55:30 +00:00
roleVals . EmailProtectionFlag = true
2016-06-22 20:08:24 +00:00
case i == 1 :
extUsage = x509 . ExtKeyUsageServerAuth
2015-06-05 18:03:57 +00:00
roleVals . ServerFlag = true
2016-06-22 20:08:24 +00:00
case i == 2 :
extUsage = x509 . ExtKeyUsageClientAuth
2015-06-05 18:03:57 +00:00
roleVals . ClientFlag = true
default :
2016-06-22 20:08:24 +00:00
extUsage = x509 . ExtKeyUsageCodeSigning
2015-06-05 18:03:57 +00:00
roleVals . CodeSigningFlag = true
}
allowed := allowedInt . ( bool )
issueVals . CommonName = name
2015-10-02 18:27:30 +00:00
if roleVals . EmailProtectionFlag {
2015-11-23 19:15:32 +00:00
if ! strings . HasPrefix ( name , "*" ) {
issueVals . CommonName = "user@" + issueVals . CommonName
}
2015-10-02 18:27:30 +00:00
}
2016-02-20 02:39:40 +00:00
issueTestStep . ErrorOk = ! allowed
2015-06-05 18:03:57 +00:00
2015-08-27 19:24:37 +00:00
validity , _ := time . ParseDuration ( roleVals . MaxTTL )
2016-02-22 18:35:57 +00:00
var testBitSize int
2015-10-02 19:47:45 +00:00
if useCSRs {
2016-02-20 02:39:40 +00:00
rsaKeyBits := [ ] int { 2048 , 4096 }
ecKeyBits := [ ] int { 224 , 256 , 384 , 521 }
2015-10-02 19:47:45 +00:00
var privKey crypto . Signer
2016-07-01 21:27:35 +00:00
var ok bool
2015-10-02 19:47:45 +00:00
switch roleVals . KeyType {
case "rsa" :
2016-02-20 02:39:40 +00:00
roleVals . KeyBits = rsaKeyBits [ mathRand . Int ( ) % 2 ]
// If we don't expect an error already, randomly choose a
// key size and expect an error if it's less than the role
// setting
2016-02-22 18:35:57 +00:00
testBitSize = roleVals . KeyBits
if ! keybitSizeRandOff && ! issueTestStep . ErrorOk {
2016-02-20 02:39:40 +00:00
testBitSize = rsaKeyBits [ mathRand . Int ( ) % 2 ]
}
if testBitSize < roleVals . KeyBits {
issueTestStep . ErrorOk = true
}
2016-07-01 21:27:35 +00:00
privKey , ok = generatedRSAKeys [ testBitSize ]
if ! ok {
privKey , _ = rsa . GenerateKey ( rand . Reader , testBitSize )
generatedRSAKeys [ testBitSize ] = privKey
}
2016-02-20 02:39:40 +00:00
2015-10-02 19:47:45 +00:00
case "ec" :
2016-02-20 02:39:40 +00:00
roleVals . KeyBits = ecKeyBits [ mathRand . Int ( ) % 4 ]
2015-10-02 19:47:45 +00:00
var curve elliptic . Curve
2016-02-20 02:39:40 +00:00
// If we don't expect an error already, randomly choose a
// key size and expect an error if it's less than the role
// setting
2016-02-22 18:35:57 +00:00
testBitSize = roleVals . KeyBits
if ! keybitSizeRandOff && ! issueTestStep . ErrorOk {
2016-02-20 02:39:40 +00:00
testBitSize = ecKeyBits [ mathRand . Int ( ) % 4 ]
}
switch testBitSize {
2015-10-02 19:47:45 +00:00
case 224 :
curve = elliptic . P224 ( )
case 256 :
curve = elliptic . P256 ( )
case 384 :
curve = elliptic . P384 ( )
case 521 :
curve = elliptic . P521 ( )
}
2016-02-20 02:39:40 +00:00
if curve . Params ( ) . BitSize < roleVals . KeyBits {
issueTestStep . ErrorOk = true
}
2016-07-01 21:27:35 +00:00
privKey , ok = generatedECKeys [ testBitSize ]
if ! ok {
privKey , _ = ecdsa . GenerateKey ( curve , rand . Reader )
generatedECKeys [ testBitSize ] = privKey
}
2015-10-02 19:47:45 +00:00
}
templ := & x509 . CertificateRequest {
Subject : pkix . Name {
CommonName : issueVals . CommonName ,
} ,
}
csr , err := x509 . CreateCertificateRequest ( rand . Reader , templ , privKey )
if err != nil {
t . Fatalf ( "Error creating certificate request: %s" , err )
}
block := pem . Block {
Type : "CERTIFICATE REQUEST" ,
Bytes : csr ,
}
issueVals . CSR = strings . TrimSpace ( string ( pem . EncodeToMemory ( & block ) ) )
2016-02-22 18:35:57 +00:00
2016-06-22 20:08:24 +00:00
addTests ( getCnCheck ( issueVals . CommonName , roleVals , privKey , x509 . KeyUsage ( parsedKeyUsage ) , extUsage , validity ) )
2015-10-02 19:47:45 +00:00
} else {
2016-06-22 20:08:24 +00:00
addTests ( getCnCheck ( issueVals . CommonName , roleVals , nil , x509 . KeyUsage ( parsedKeyUsage ) , extUsage , validity ) )
2015-10-02 19:47:45 +00:00
}
2015-06-05 18:03:57 +00:00
}
}
// Common Name tests
{
// common_name not provided
issueVals . CommonName = ""
issueTestStep . ErrorOk = true
addTests ( nil )
// Nothing is allowed
addCnTests ( )
roleVals . AllowLocalhost = true
commonNames . Localhost = true
addCnTests ( )
2015-12-01 04:49:11 +00:00
roleVals . AllowedDomains = "foobar.com"
2015-06-05 18:03:57 +00:00
addCnTests ( )
2015-12-01 04:49:11 +00:00
roleVals . AllowedDomains = "example.com"
2015-10-02 18:27:30 +00:00
roleVals . AllowSubdomains = true
2015-10-02 16:22:02 +00:00
commonNames . SubDomain = true
2015-06-05 18:03:57 +00:00
commonNames . Wildcard = true
2015-10-02 18:27:30 +00:00
commonNames . SubSubdomain = true
commonNames . SubSubdomainWildcard = true
2015-06-05 18:03:57 +00:00
addCnTests ( )
2015-12-01 04:49:11 +00:00
roleVals . AllowedDomains = "foobar.com,example.com"
commonNames . SecondDomain = true
roleVals . AllowBareDomains = true
commonNames . BareDomain = true
2015-10-02 16:22:02 +00:00
addCnTests ( )
2015-06-05 18:03:57 +00:00
roleVals . AllowAnyName = true
2015-08-20 21:33:37 +00:00
roleVals . EnforceHostnames = true
2015-06-05 18:03:57 +00:00
commonNames . AnyHost = true
addCnTests ( )
2015-08-20 21:33:37 +00:00
roleVals . EnforceHostnames = false
commonNames . NonHostname = true
addCnTests ( )
2016-02-22 18:35:57 +00:00
// Ensure that we end up with acceptable key sizes since they won't be
// toggled any longer
keybitSizeRandOff = true
addCnTests ( )
2015-06-05 18:03:57 +00:00
}
// IP SAN tests
{
issueVals . IPSANs = "127.0.0.1,::1"
issueTestStep . ErrorOk = true
addTests ( nil )
roleVals . AllowIPSANs = true
issueTestStep . ErrorOk = false
addTests ( nil )
issueVals . IPSANs = "foobar"
issueTestStep . ErrorOk = true
addTests ( nil )
issueTestStep . ErrorOk = false
issueVals . IPSANs = ""
}
// Lease tests
{
roleTestStep . ErrorOk = true
roleVals . Lease = ""
2015-08-27 19:24:37 +00:00
roleVals . MaxTTL = ""
2015-06-05 18:03:57 +00:00
addTests ( nil )
roleVals . Lease = "12h"
2015-08-27 19:24:37 +00:00
roleVals . MaxTTL = "6h"
2015-06-05 18:03:57 +00:00
addTests ( nil )
roleTestStep . ErrorOk = false
}
2016-01-28 20:18:07 +00:00
// Listing test
ret = append ( ret , logicaltest . TestStep {
Operation : logical . ListOperation ,
Path : "roles/" ,
Check : func ( resp * logical . Response ) error {
if resp . Data == nil {
return fmt . Errorf ( "nil data" )
}
keysRaw , ok := resp . Data [ "keys" ]
if ! ok {
return fmt . Errorf ( "no keys found" )
}
keys , ok := keysRaw . ( [ ] string )
if ! ok {
return fmt . Errorf ( "could not convert keys to a string list" )
}
if len ( keys ) != 1 {
return fmt . Errorf ( "unexpected keys length of %d" , len ( keys ) )
}
if keys [ 0 ] != "test" {
2016-04-13 19:38:29 +00:00
return fmt . Errorf ( "unexpected key value of %s" , keys [ 0 ] )
2016-01-28 20:18:07 +00:00
}
return nil
} ,
} )
2015-06-05 18:03:57 +00:00
return ret
}
2016-06-08 15:46:58 +00:00
func TestBackend_PathFetchCertList ( t * testing . T ) {
// create the backend
config := logical . TestBackendConfig ( )
storage := & logical . InmemStorage { }
config . StorageView = storage
b := Backend ( )
_ , err := b . Setup ( config )
if err != nil {
t . Fatal ( err )
}
// generate root
rootData := map [ string ] interface { } {
"common_name" : "test.com" ,
"ttl" : "6h" ,
}
resp , err := b . HandleRequest ( & logical . Request {
Operation : logical . UpdateOperation ,
Path : "root/generate/internal" ,
Storage : storage ,
Data : rootData ,
} )
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to generate root, %#v" , resp )
}
if err != nil {
t . Fatal ( err )
}
// config urls
urlsData := map [ string ] interface { } {
"issuing_certificates" : "http://127.0.0.1:8200/v1/pki/ca" ,
"crl_distribution_points" : "http://127.0.0.1:8200/v1/pki/crl" ,
}
resp , err = b . HandleRequest ( & logical . Request {
Operation : logical . UpdateOperation ,
Path : "config/urls" ,
Storage : storage ,
Data : urlsData ,
} )
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to config urls, %#v" , resp )
}
if err != nil {
t . Fatal ( err )
}
// create a role entry
roleData := map [ string ] interface { } {
"allowed_domains" : "test.com" ,
"allow_subdomains" : "true" ,
"max_ttl" : "4h" ,
}
resp , err = b . HandleRequest ( & logical . Request {
Operation : logical . UpdateOperation ,
Path : "roles/test-example" ,
Storage : storage ,
Data : roleData ,
} )
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to create a role, %#v" , resp )
}
if err != nil {
t . Fatal ( err )
}
2016-06-08 16:49:10 +00:00
// issue some certs
i := 1
for i < 10 {
certData := map [ string ] interface { } {
"common_name" : "example.test.com" ,
}
resp , err = b . HandleRequest ( & logical . Request {
Operation : logical . UpdateOperation ,
Path : "issue/test-example" ,
Storage : storage ,
Data : certData ,
} )
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to issue a cert, %#v" , resp )
}
if err != nil {
t . Fatal ( err )
}
i = i + 1
2016-06-08 15:46:58 +00:00
}
2016-06-08 16:49:10 +00:00
// list certs
2016-06-08 15:46:58 +00:00
resp , err = b . HandleRequest ( & logical . Request {
2016-06-08 16:49:10 +00:00
Operation : logical . ListOperation ,
Path : "certs" ,
2016-06-08 15:46:58 +00:00
Storage : storage ,
} )
if resp != nil && resp . IsError ( ) {
2016-06-08 16:49:10 +00:00
t . Fatalf ( "failed to list certs, %#v" , resp )
2016-06-08 15:46:58 +00:00
}
if err != nil {
t . Fatal ( err )
}
2016-06-08 16:49:10 +00:00
// check that the root and 9 additional certs are all listed
if len ( resp . Data [ "keys" ] . ( [ ] string ) ) != 10 {
t . Fatalf ( "failed to list all 10 certs" )
}
2016-06-08 15:46:58 +00:00
2016-06-08 16:49:10 +00:00
// list certs/
2016-06-08 15:46:58 +00:00
resp , err = b . HandleRequest ( & logical . Request {
Operation : logical . ListOperation ,
2016-06-08 16:49:10 +00:00
Path : "certs/" ,
2016-06-08 15:46:58 +00:00
Storage : storage ,
} )
if resp != nil && resp . IsError ( ) {
t . Fatalf ( "failed to list certs, %#v" , resp )
}
if err != nil {
t . Fatal ( err )
}
2016-06-08 16:49:10 +00:00
// check that the root and 9 additional certs are all listed
if len ( resp . Data [ "keys" ] . ( [ ] string ) ) != 10 {
t . Fatalf ( "failed to list all 10 certs" )
}
2016-06-08 15:46:58 +00:00
}
2015-06-05 18:03:57 +00:00
const (
2015-10-05 17:00:45 +00:00
rsaCAKey string = ` -- -- - BEGIN RSA PRIVATE KEY -- -- -
2015-06-05 18:03:57 +00:00
MIIEpAIBAAKCAQEA1eKB2nFbRqTFs7KyZjbzB5VRCBbnLZfEXVP1c3bHe + YGjlfl
34 cy52dmancUzOf1 / Jfo + VglocjTLVy5wHSGJwQYs8b6pEuuvAVo / 6 wUL5Z7ZlQD
R4kDe5Q + xgoRT6Bi / Bs57E + fNYgyUq / YAUY5WLuC + ZliCbJkLnb15ItuP1yVUTDX
TYORRE3qJS5RRol8D3QvteG9LyPEc7C + jsm5iBCagyxluzU0dnEOib5q7xwZncoM
bQz + rZH3QnwOij41FOGRPazrD5Mv6xLBkFnE5VAJ + GIgvd4bpOwvYMuofvF4PS7S
FzxkGssMLlICap6PFpKz86DpAoDxPuoZeOhU4QIDAQABAoIBAQCp6VIdFdZcDYPd
WIVuvBJfINiJo6AtURa2yX8BJggdPkRRCjTcWUwwFq1 + wHDuwwtgidGTW9oxZxeU
Psh1wlvcXN2 + 28 C7ikAar / WUvsAeed44EV + 1 kXwJzV / 89 XyBFDnuazadqzcgUL0h
gP4JLR9bhULsRFRkvanmW6zFzZpcjBzi / UoFuWkFRRqZ0euM2Lpz8L75PFfW9s9M
kNglZpcV6ZmvR9c1JkEMUs / mrB8ZgCd1uvmcVosQ + u7sE8Yk / xAurHXuNJQlGXx4
azrLW0XY1CLO2Tm4l4MwPjmhH0WytXNjOSKycBCXVnBIfZsI128DsP5YyA / fW9qA
BAqFSzABAoGBAPcBNk9sf3cnZ5w6qwlE2ysDwGIGR + I1fb09YjRI6vjwwdWZgGR0
EE4UB1Pp + KIehXaTJHcEgvBBErM2NLS4qKzh25O30C2EwK6o //3jEAribuYutBhJ
ihu1qKzqcPbKClG + 34 kjX6nmtux2wlYM05f5v3ALki5Is7W / RrfceBuBAoGBAN2s
hdt4TcgIcZymPG2931qCBGF3E8AaA8bUl9TKaZHuFikOMFKA / KM5O5mznPGnQP2d
kXYKXuqdYhVLwp32FTbIbozGZZ8XliO5oS7J3vIID + sLWQhrvyFO7d0lpSjv41HH
yJ2DrykHRg8hxsbh2D4By7olBx6Q2m + B8lPzHmlhAoGACHUeKvIIG0haH9tSZ + rX
pk1mlPSqGXDDcWtcpXWptgRoXqv23Xmr5UCCT7k / Li3lW / 4 FzZ117kwMG97LRzTb
ca / 6 GMC + fBCDmHdo7ISN1BGUwoTu3bYG6JP7xo / wdkLMv6fNd6CicerYcJhQZynh
RN7kUy3SP4t1u89k2H7QDgECgYBpU0bKr8 + tQq3Qs3 + 02 OmeFHbGZJDCztmKiIqX
tZERoGFxIme9W8IuP8xczGW + wCx2FH7 / 6 g + NRDhNTBDtgvYzcGpugvnX7JoO4W1 /
ULWYpFID6QFlqeRHjDwivndKCykkO1vL07zPLsCQAglzh + 16 ENpe2KcYU9Ul9EVS
tAp4IQKBgQDrb / NpiVx7NI6PyTCm6ctuUAYm3ihAiQNV4Bmr0liPDp9PozbqkhcF
udNtivO4LlRb / PJ + DK6afDyH8aJQdDqe3NpDvyrmKiMSYOY3iVFvan4tbIiofxdQ
flwiZUzox814fzXbxheO9Cs6pXz7PUBVU4fN0Y / hXJCfRO4Ns9152A ==
-- -- - END RSA PRIVATE KEY -- -- -
`
2015-10-05 17:00:45 +00:00
rsaCACert string = ` -- -- - BEGIN CERTIFICATE -- -- -
2015-06-05 18:03:57 +00:00
MIIDUTCCAjmgAwIBAgIJAKM + z4MSfw2mMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV
BAMMEFZhdWx0IFRlc3RpbmcgQ0EwHhcNMTUwNjAxMjA1MTUzWhcNMjUwNTI5MjA1
MTUzWjAbMRkwFwYDVQQDDBBWYXVsdCBUZXN0aW5nIENBMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEA1eKB2nFbRqTFs7KyZjbzB5VRCBbnLZfEXVP1c3bH
e + YGjlfl34cy52dmancUzOf1 / Jfo + VglocjTLVy5wHSGJwQYs8b6pEuuvAVo / 6 wU
L5Z7ZlQDR4kDe5Q + xgoRT6Bi / Bs57E + fNYgyUq / YAUY5WLuC + ZliCbJkLnb15Itu
P1yVUTDXTYORRE3qJS5RRol8D3QvteG9LyPEc7C + jsm5iBCagyxluzU0dnEOib5q
7 xwZncoMbQz + rZH3QnwOij41FOGRPazrD5Mv6xLBkFnE5VAJ + GIgvd4bpOwvYMuo
fvF4PS7SFzxkGssMLlICap6PFpKz86DpAoDxPuoZeOhU4QIDAQABo4GXMIGUMB0G
A1UdDgQWBBTknN5eFxxo5aTlfq + G4ZXs3AsxWTAfBgNVHSMEGDAWgBTknN5eFxxo
5 aTlfq + G4ZXs3AsxWTAxBgNVHR8EKjAoMCagJKAihiBodHRwOi8vbG9jYWxob3N0
OjgyMDAvdjEvcGtpL2NybDAPBgNVHRMBAf8EBTADAQH / MA4GA1UdDwEB / wQEAwIB
BjANBgkqhkiG9w0BAQsFAAOCAQEAsINcA4PZm + OyldgNrwRVgxoSrhV1I9zszhc9
VV340ZWlpTTxFKVb / K5Hg + jMF9tv70X1HwlYdlutE6KdrsA3gks5zanh4 / 3 zlrYk
ABNBmSD6SSU2HKX1bFCBAAS3YHONE5o1K5tzwLsMl5uilNf + Wid3NjFnQ4KfuYI5
loN / opnM6 + a / O3Zua8RAuMMAv9wyqwn88aVuLvVzDNSMe5qC5kkuLGmRkNgY06rI
S / fXIHIOldeQxgYCqhdVmcDWJ1PtVaDfBsKVpRg1GRU8LUGw2E4AY + twd + J2FBfa
G / 7 g4koczXLoUM3OQXd5Aq2cs4SS1vODrYmgbioFsQ3eDHd1fg ==
-- -- - END CERTIFICATE -- -- -
2015-10-05 17:00:45 +00:00
`
ecCAKey string = ` -- -- - BEGIN EC PRIVATE KEY -- -- -
MIGkAgEBBDBP / t89wrC0RFVs0N + jiRuGPptoxI1Iyu42 / PzzZWMKYnO7yCWFG / Qv
zC8cRa8PDqegBwYFK4EEACKhZANiAAQI9e8n9RD6gOd5YpWpDi5AoPbskxQSogxx
dYFzzHwS0RYIucmlcJ2CuJQNc + 9E4 dUCMsYr2cAnCgA4iUHzGaje3Fa4O667LVH1
imAyAj5nbfSd89iNzg4XNPkFjuVNBlE =
-- -- - END EC PRIVATE KEY -- -- -
`
ecCACert string = ` -- -- - BEGIN CERTIFICATE -- -- -
MIIDHzCCAqSgAwIBAgIUEQ4L + 8 Xl9 + / uxU3MMCrd3Bw0HMcwCgYIKoZIzj0EAwIw
XzEjMCEGA1UEAxMaVmF1bHQgRUMgdGVzdGluZyByb290IGNlcnQxODA2BgNVBAUT
Lzk3MzY2MDk3NDQ1ODU2MDI3MDY5MDQ0MTkxNjIxODI4NjI0NjM0NTI5MTkzMTU5
MB4XDTE1MTAwNTE2MzAwMFoXDTM1MDkzMDE2MzAwMFowXzEjMCEGA1UEAxMaVmF1
bHQgRUMgdGVzdGluZyByb290IGNlcnQxODA2BgNVBAUTLzk3MzY2MDk3NDQ1ODU2
MDI3MDY5MDQ0MTkxNjIxODI4NjI0NjM0NTI5MTkzMTU5MHYwEAYHKoZIzj0CAQYF
K4EEACIDYgAECPXvJ / UQ + oDneWKVqQ4uQKD27JMUEqIMcXWBc8x8EtEWCLnJpXCd
griUDXPvROHVAjLGK9nAJwoAOIlB8xmo3txWuDuuuy1R9YpgMgI + Z230nfPYjc4O
FzT5BY7lTQZRo4IBHzCCARswDgYDVR0PAQH / BAQDAgGuMBMGA1UdJQQMMAoGCCsG
AQUFBwMJMA8GA1UdEwEB / wQFMAMBAf8wHQYDVR0OBBYEFCIBqs15CiKuj7vqmIW5
L07WSeLhMB8GA1UdIwQYMBaAFCIBqs15CiKuj7vqmIW5L07WSeLhMEIGCCsGAQUF
BwEBBDYwNDAyBggrBgEFBQcwAoYmaHR0cDovL3ZhdWx0LmV4YW1wbGUuY29tL3Yx
L3Jvb3Rwa2kvY2EwJQYDVR0RBB4wHIIaVmF1bHQgRUMgdGVzdGluZyByb290IGNl
cnQwOAYDVR0fBDEwLzAtoCugKYYnaHR0cDovL3ZhdWx0LmV4YW1wbGUuY29tL3Yx
L3Jvb3Rwa2kvY3JsMAoGCCqGSM49BAMCA2kAMGYCMQDRrxXskBtXjuZ1tUTk + qae
3 bNVE1oeTDJhe0m3KN7qTykSGslxfEjlv83GYXziiv0CMQDsqu1U9uXPn3ezSbgG
O30prQ / sanDzNAeJhftoGtNPJDspwx0fzclHvKIhgl3JVUc =
-- -- - END CERTIFICATE -- -- -
2015-06-05 18:03:57 +00:00
`
)