2015-05-15 16:13:05 +00:00
package pki
import (
"encoding/pem"
"fmt"
"strings"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
func pathFetchCA ( b * backend ) * framework . Path {
return & framework . Path {
Pattern : ` ca(/pem)? ` ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . ReadOperation : b . pathFetchRead ,
} ,
HelpSynopsis : pathFetchHelpSyn ,
HelpDescription : pathFetchHelpDesc ,
}
}
func pathFetchCRL ( b * backend ) * framework . Path {
return & framework . Path {
Pattern : ` crl(/pem)? ` ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . ReadOperation : b . pathFetchRead ,
} ,
HelpSynopsis : pathFetchHelpSyn ,
HelpDescription : pathFetchHelpDesc ,
}
}
func pathFetchValid ( b * backend ) * framework . Path {
return & framework . Path {
Pattern : ` cert/(?P<serial>[0-9A-Fa-f-:]+) ` ,
Fields : map [ string ] * framework . FieldSchema {
"serial" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Certificate serial number, in colon- or hyphen-separated octal" ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . ReadOperation : b . pathFetchRead ,
} ,
HelpSynopsis : pathFetchHelpSyn ,
HelpDescription : pathFetchHelpDesc ,
}
}
func pathFetchCRLViaCertPath ( b * backend ) * framework . Path {
return & framework . Path {
Pattern : ` cert/crl ` ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . ReadOperation : b . pathFetchRead ,
} ,
HelpSynopsis : pathFetchHelpSyn ,
HelpDescription : pathFetchHelpDesc ,
}
}
func pathFetchRevoked ( b * backend ) * framework . Path {
return & framework . Path {
Pattern : ` revoked/(?P<serial>[0-9A-Fa-f-:]+) ` ,
Fields : map [ string ] * framework . FieldSchema {
"serial" : & framework . FieldSchema {
Type : framework . TypeString ,
Description : "Certificate serial number, in colon- or hyphen-separated octal" ,
} ,
} ,
Callbacks : map [ logical . Operation ] framework . OperationFunc {
logical . ReadOperation : b . pathFetchRead ,
} ,
HelpSynopsis : pathFetchHelpSyn ,
HelpDescription : pathFetchHelpDesc ,
}
}
func ( b * backend ) pathFetchRead ( req * logical . Request , data * framework . FieldData ) ( response * logical . Response , retErr error ) {
var serial string
var pemType string
var contentType string
var certEntry * logical . StorageEntry
2015-06-15 17:33:23 +00:00
var userErr , intErr error
2015-05-15 16:13:05 +00:00
var certificate [ ] byte
response = & logical . Response {
Data : map [ string ] interface { } { } ,
}
switch {
case req . Path == "ca" || req . Path == "ca/pem" :
serial = "ca"
contentType = "application/pkix-cert"
if req . Path == "ca/pem" {
pemType = "CERTIFICATE"
}
case req . Path == "crl" || req . Path == "crl/pem" :
serial = "crl"
contentType = "application/pkix-crl"
if req . Path == "crl/pem" {
pemType = "X509 CRL"
}
case req . Path == "cert/crl" :
serial = "crl"
pemType = "X509 CRL"
default :
serial = data . Get ( "serial" ) . ( string )
pemType = "CERTIFICATE"
}
if len ( serial ) == 0 {
response = logical . ErrorResponse ( "The serial number must be provided" )
goto reply
}
2015-06-15 17:33:23 +00:00
_ , _ , userErr , intErr = fetchCAInfo ( req )
switch {
case userErr != nil :
response = logical . ErrorResponse ( fmt . Sprintf ( "%s" , userErr ) )
goto reply
case intErr != nil :
retErr = intErr
2015-05-15 16:13:05 +00:00
goto reply
}
certEntry , userErr , intErr = fetchCertBySerial ( req , req . Path , serial )
switch {
case userErr != nil :
response = logical . ErrorResponse ( userErr . Error ( ) )
goto reply
case intErr != nil :
retErr = intErr
goto reply
}
switch {
case strings . HasPrefix ( req . Path , "revoked/" ) :
var revInfo revocationInfo
err := certEntry . DecodeJSON ( & revInfo )
if err != nil {
retErr = fmt . Errorf ( "Error decoding revocation entry for serial %s: %s" , serial , err )
goto reply
}
certificate = revInfo . CertificateBytes
response . Data [ "revocation_time" ] = revInfo . RevocationTime
default :
certificate = certEntry . Value
}
if len ( pemType ) != 0 {
block := pem . Block {
Type : pemType ,
Bytes : certEntry . Value ,
}
certificate = pem . EncodeToMemory ( & block )
}
reply :
switch {
case len ( contentType ) != 0 :
response = & logical . Response {
Data : map [ string ] interface { } {
logical . HTTPContentType : contentType ,
logical . HTTPRawBody : certificate ,
} }
if retErr != nil {
b . Logger ( ) . Printf ( "Possible error, but cannot return in raw response: %s. Note that an empty CA probably means none was configured, and an empty CRL is quite possibly correct" , retErr )
}
retErr = nil
response . Data [ logical . HTTPStatusCode ] = 200
case retErr != nil :
response = nil
default :
response . Data [ "certificate" ] = string ( certificate )
}
return
}
const pathFetchHelpSyn = `
Fetch a CA , CRL , valid or revoked certificate .
`
const pathFetchHelpDesc = `
This allows certificates to be fetched . If using the fetch / prefix any valid certificate can be fetched ; if using the revoked / prefix , which requires a root token , revoked certificates can also be fetched .
Using "ca" or "crl" as the value fetches the appropriate information in DER encoding . Add "/pem" to either to get PEM encoding .
`