Add sign method (untested)

This commit is contained in:
Jeff Mitchell
2015-09-29 18:48:31 -07:00
parent 667d5cafd3
commit 62049cd059
4 changed files with 85 additions and 25 deletions

View File

@@ -43,6 +43,7 @@ func Backend() *framework.Backend {
pathSetCA(&b),
pathConfigCA(&b),
pathConfigCRL(&b),
pathSign(&b),
pathIssue(&b),
pathRotateCRL(&b),
pathFetchCA(&b),

View File

@@ -9,6 +9,7 @@ import (
"crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"net"
@@ -215,7 +216,6 @@ func generateCSR(b *backend,
func signCert(b *backend,
role *roleEntry,
signingBundle *certutil.ParsedCertBundle,
csr *x509.CertificateRequest,
isCA bool,
req *logical.Request,
data *framework.FieldData) (*certutil.ParsedCertBundle, error) {
@@ -225,6 +225,22 @@ func signCert(b *backend,
return nil, certutil.UserError{Err: "The common_name field is required"}
}
csrString := req.Data["csr"].(string)
if csrString == "" {
return nil, certutil.UserError{Err: fmt.Sprintf(
"\"csr\" is empty")}
}
pemBytes := []byte(csrString)
pemBlock, pemBytes := pem.Decode(pemBytes)
if pemBlock == nil {
return nil, certutil.UserError{Err: "csr contains no data"}
}
csr, err := x509.ParseCertificateRequest(pemBlock.Bytes)
if err != nil {
return nil, certutil.UserError{Err: "certificate request could not be parsed"}
}
creationBundle, err := generateCreationBundle(b, role, signingBundle, isCA, req, data)
if err != nil {
return nil, err

View File

@@ -1,8 +1,6 @@
package pki
import (
"crypto/x509"
"encoding/pem"
"fmt"
"reflect"
"strings"
@@ -413,22 +411,6 @@ func (b *backend) pathCASignWrite(
pkiAddress = pkiAddress[:len(pkiAddress)-1]
}
csrString := req.Data["csr"].(string)
if csrString == "" {
return logical.ErrorResponse(fmt.Sprintf(
"\"csr\" is empty")), nil
}
pemBytes := []byte(csrString)
pemBlock, pemBytes := pem.Decode(pemBytes)
if pemBlock == nil {
return nil, certutil.UserError{Err: "csr contains no data"}
}
csr, err := x509.ParseCertificateRequest(pemBlock.Bytes)
if err != nil {
return nil, certutil.UserError{Err: "certificate request could not be parsed"}
}
req.Data["pki_address"] = pkiAddress
role := &roleEntry{
@@ -464,7 +446,7 @@ func (b *backend) pathCASignWrite(
"Error fetching CA certificate: %s", caErr)}
}
parsedBundle, err := signCert(b, role, signingBundle, csr, true, req, data)
parsedBundle, err := signCert(b, role, signingBundle, true, req, data)
if err != nil {
switch err.(type) {
case certutil.UserError:

View File

@@ -44,10 +44,6 @@ the role default, backend default, or system
default TTL is used, in that order. Cannot
be later than the role max TTL.`,
},
"csr": &framework.FieldSchema{
Type: framework.TypeString,
Description: `PEM-format CSR to be signed.`,
},
}
func pathIssue(b *backend) *framework.Path {
@@ -65,7 +61,7 @@ func pathIssue(b *backend) *framework.Path {
}
func pathSign(b *backend) *framework.Path {
return &framework.Path{
ret := &framework.Path{
Pattern: "sign/" + framework.GenericNameRegex("role"),
Fields: issueAndSignSchema,
@@ -76,6 +72,13 @@ func pathSign(b *backend) *framework.Path {
HelpSynopsis: pathIssueCertHelpSyn,
HelpDescription: pathIssueCertHelpDesc,
}
ret.Fields["csr"] = &framework.FieldSchema{
Type: framework.TypeString,
Description: `PEM-format CSR to be signed.`,
}
return ret
}
func (b *backend) pathIssueCert(
@@ -136,6 +139,64 @@ func (b *backend) pathIssueCert(
return resp, nil
}
func (b *backend) pathSignCSR(
req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
roleName := data.Get("role").(string)
// Get the role
role, err := b.getRole(req.Storage, roleName)
if err != nil {
return nil, err
}
if role == nil {
return logical.ErrorResponse(fmt.Sprintf("Unknown role: %s", roleName)), nil
}
var caErr error
signingBundle, caErr := fetchCAInfo(req)
switch caErr.(type) {
case certutil.UserError:
return nil, certutil.UserError{Err: fmt.Sprintf(
"Could not fetch the CA certificate (was one set?): %s", caErr)}
case certutil.InternalError:
return nil, certutil.InternalError{Err: fmt.Sprintf(
"Error fetching CA certificate: %s", caErr)}
}
parsedBundle, err := signCert(b, role, signingBundle, false, req, data)
if err != nil {
switch err.(type) {
case certutil.UserError:
return logical.ErrorResponse(err.Error()), nil
case certutil.InternalError:
return nil, err
}
}
cb, err := parsedBundle.ToCertBundle()
if err != nil {
return nil, fmt.Errorf("Error converting raw cert bundle to cert bundle: %s", err)
}
resp := b.Secret(SecretCertsType).Response(
structs.New(cb).Map(),
map[string]interface{}{
"serial_number": cb.SerialNumber,
})
resp.Secret.TTL = parsedBundle.Certificate.NotAfter.Sub(time.Now())
err = req.Storage.Put(&logical.StorageEntry{
Key: "certs/" + cb.SerialNumber,
Value: parsedBundle.CertificateBytes,
})
if err != nil {
return nil, fmt.Errorf("Unable to store certificate locally")
}
return resp, nil
}
const pathIssueCertHelpSyn = `
Request certificates using a certain role with the provided common name.
`