open-vault/builtin/logical/pki/path_fetch.go
Jeff Mitchell a6fc48b854 A few things:
* Add comments to every non-obvious (e.g. not basic read/write handler type) function
* Remove revoked/ endpoint, at least for now
* Add configurable CRL lifetime
* Cleanup
* Address some comments from code review

Commit contents (C)2015 Akamai Technologies, Inc. <opensource@akamai.com>
2015-06-19 12:48:18 -04:00

178 lines
4.4 KiB
Go

package pki
import (
"encoding/pem"
"fmt"
"github.com/hashicorp/vault/helper/certutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
// Returns the CA in raw format
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,
}
}
// Returns the CRL in raw format
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,
}
}
// Returns any valid (non-revoked) cert. Since "ca" fits the pattern, this path
// also handles returning the CA cert in a non-raw format.
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,
}
}
// This returns the CRL in a non-raw format
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 (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
var funcErr error
var certificate []byte
response = &logical.Response{
Data: map[string]interface{}{},
}
// Some of these need to return raw and some non-raw;
// this is basically handled by setting contentType or not.
// Errors don't cause an immediate exit, because the raw
// paths still need to return raw output.
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
}
_, funcErr = fetchCAInfo(req)
switch funcErr.(type) {
case certutil.UserError:
response = logical.ErrorResponse(fmt.Sprintf("%s", funcErr))
goto reply
case certutil.InternalError:
retErr = funcErr
goto reply
}
certEntry, funcErr = fetchCertBySerial(req, req.Path, serial)
switch funcErr.(type) {
case certutil.UserError:
response = logical.ErrorResponse(funcErr.Error())
goto reply
case certutil.InternalError:
retErr = funcErr
goto reply
}
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, or non-revoked certificate.
`
const pathFetchHelpDesc = `
This allows certificates to be fetched. If using the fetch/ prefix any non-revoked certificate can be fetched.
Using "ca" or "crl" as the value fetches the appropriate information in DER encoding. Add "/pem" to either to get PEM encoding.
`