Allow the format to be specified as pem_bundle, which creates a

concatenated PEM file.

Fixes #992
This commit is contained in:
Jeff Mitchell 2016-02-01 13:19:41 -05:00
parent 0f5db5da6c
commit fc6d23a54e
7 changed files with 85 additions and 29 deletions

View file

@ -22,7 +22,7 @@ func (b *backend) getGenerationParams(
format = getFormat(data) format = getFormat(data)
if format == "" { if format == "" {
errorResp = logical.ErrorResponse( errorResp = logical.ErrorResponse(
`The "format" path parameter must be "pem" or "der"`) `The "format" path parameter must be "pem", "der", or "pem_bundle"`)
return return
} }

View file

@ -74,6 +74,7 @@ func getFormat(data *framework.FieldData) string {
switch format { switch format {
case "pem": case "pem":
case "der": case "der":
case "pem_bundle":
default: default:
format = "" format = ""
} }

View file

@ -8,8 +8,10 @@ func addIssueAndSignCommonFields(fields map[string]*framework.FieldSchema) map[s
fields["format"] = &framework.FieldSchema{ fields["format"] = &framework.FieldSchema{
Type: framework.TypeString, Type: framework.TypeString,
Default: "pem", Default: "pem",
Description: `Format for returned data. Can be "pem" or "der"; Description: `Format for returned data. Can be "pem", "der",
defaults to "pem".`, or "pem_bundle". If "pem_bundle" any private
private key and issuing cert will be appended
to the certificate pem. Defaults to "pem".`,
} }
fields["ip_sans"] = &framework.FieldSchema{ fields["ip_sans"] = &framework.FieldSchema{

View file

@ -88,6 +88,15 @@ func (b *backend) pathGenerateIntermediate(
resp.Data["private_key"] = csrb.PrivateKey resp.Data["private_key"] = csrb.PrivateKey
resp.Data["private_key_type"] = csrb.PrivateKeyType resp.Data["private_key_type"] = csrb.PrivateKeyType
} }
case "pem_bundle":
resp.Data["csr"] = csrb.CSR
if exported {
resp.Data["csr"] = fmt.Sprintf("%s\n%s", csrb.PrivateKey, csrb.CSR)
resp.Data["private_key"] = csrb.PrivateKey
resp.Data["private_key_type"] = csrb.PrivateKeyType
}
case "der": case "der":
resp.Data["csr"] = base64.StdEncoding.EncodeToString(parsedBundle.CSRBytes) resp.Data["csr"] = base64.StdEncoding.EncodeToString(parsedBundle.CSRBytes)
if exported { if exported {

View file

@ -133,7 +133,7 @@ func (b *backend) pathIssueSignCert(
format := getFormat(data) format := getFormat(data)
if format == "" { if format == "" {
return logical.ErrorResponse( return logical.ErrorResponse(
`The "format" path parameter must be "pem" or "der"`), nil `The "format" path parameter must be "pem", "der", or "pem_bundle"`), nil
} }
var caErr error var caErr error
@ -172,18 +172,31 @@ func (b *backend) pathIssueSignCert(
map[string]interface{}{ map[string]interface{}{
"certificate": cb.Certificate, "certificate": cb.Certificate,
"issuing_ca": cb.IssuingCA, "issuing_ca": cb.IssuingCA,
"serial_number": cb.SerialNumber,
}, },
map[string]interface{}{ map[string]interface{}{
"serial_number": cb.SerialNumber, "serial_number": cb.SerialNumber,
}) })
switch format {
case "pem":
resp.Data["issuing_ca"] = cb.IssuingCA
resp.Data["certificate"] = cb.Certificate
if !useCSR { if !useCSR {
resp.Data["private_key"] = cb.PrivateKey resp.Data["private_key"] = cb.PrivateKey
resp.Data["private_key_type"] = cb.PrivateKeyType resp.Data["private_key_type"] = cb.PrivateKeyType
} }
if format == "der" { case "pem_bundle":
resp.Data["issuing_ca"] = cb.IssuingCA
resp.Data["certificate"] = fmt.Sprintf("%s\n%s", cb.Certificate, cb.IssuingCA)
if !useCSR {
resp.Data["private_key"] = cb.PrivateKey
resp.Data["private_key_type"] = cb.PrivateKeyType
resp.Data["certificate"] = fmt.Sprintf("%s\n%s\n%s", cb.PrivateKey, cb.Certificate, cb.IssuingCA)
}
case "der":
resp.Data["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) resp.Data["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes)
resp.Data["issuing_ca"] = base64.StdEncoding.EncodeToString(parsedBundle.IssuingCABytes) resp.Data["issuing_ca"] = base64.StdEncoding.EncodeToString(parsedBundle.IssuingCABytes)
if !useCSR { if !useCSR {

View file

@ -101,8 +101,6 @@ func (b *backend) pathCAGenerateRoot(
map[string]interface{}{ map[string]interface{}{
"expiration": int64(parsedBundle.Certificate.NotAfter.Unix()), "expiration": int64(parsedBundle.Certificate.NotAfter.Unix()),
"serial_number": cb.SerialNumber, "serial_number": cb.SerialNumber,
"certificate": cb.Certificate,
"issuing_ca": cb.IssuingCA,
}, },
map[string]interface{}{ map[string]interface{}{
"serial_number": cb.SerialNumber, "serial_number": cb.SerialNumber,
@ -110,10 +108,24 @@ func (b *backend) pathCAGenerateRoot(
switch format { switch format {
case "pem": case "pem":
resp.Data["certificate"] = cb.Certificate
resp.Data["issuing_ca"] = cb.IssuingCA
if exported { if exported {
resp.Data["private_key"] = cb.PrivateKey resp.Data["private_key"] = cb.PrivateKey
resp.Data["private_key_type"] = cb.PrivateKeyType resp.Data["private_key_type"] = cb.PrivateKeyType
} }
case "pem_bundle":
resp.Data["issuing_ca"] = cb.IssuingCA
if exported {
resp.Data["private_key"] = cb.PrivateKey
resp.Data["private_key_type"] = cb.PrivateKeyType
resp.Data["certificate"] = fmt.Sprintf("%s\n%s\n%s", cb.PrivateKey, cb.Certificate, cb.IssuingCA)
} else {
resp.Data["certificate"] = fmt.Sprintf("%s\n%s", cb.Certificate, cb.IssuingCA)
}
case "der": case "der":
resp.Data["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) resp.Data["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes)
resp.Data["issuing_ca"] = base64.StdEncoding.EncodeToString(parsedBundle.IssuingCABytes) resp.Data["issuing_ca"] = base64.StdEncoding.EncodeToString(parsedBundle.IssuingCABytes)
@ -228,14 +240,21 @@ func (b *backend) pathCASignIntermediate(
map[string]interface{}{ map[string]interface{}{
"expiration": int64(parsedBundle.Certificate.NotAfter.Unix()), "expiration": int64(parsedBundle.Certificate.NotAfter.Unix()),
"serial_number": cb.SerialNumber, "serial_number": cb.SerialNumber,
"certificate": cb.Certificate,
"issuing_ca": cb.IssuingCA,
}, },
map[string]interface{}{ map[string]interface{}{
"serial_number": cb.SerialNumber, "serial_number": cb.SerialNumber,
}) })
if format == "der" { switch format {
case "pem":
resp.Data["certificate"] = cb.Certificate
resp.Data["issuing_ca"] = cb.IssuingCA
case "pem_bundle":
resp.Data["certificate"] = fmt.Sprintf("%s\n%s", cb.Certificate, cb.IssuingCA)
resp.Data["issuing_ca"] = cb.IssuingCA
case "der":
resp.Data["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes) resp.Data["certificate"] = base64.StdEncoding.EncodeToString(parsedBundle.CertificateBytes)
resp.Data["issuing_ca"] = base64.StdEncoding.EncodeToString(parsedBundle.IssuingCABytes) resp.Data["issuing_ca"] = base64.StdEncoding.EncodeToString(parsedBundle.IssuingCABytes)
} }

View file

@ -741,8 +741,10 @@ subpath for interactive help output.
<li> <li>
<span class="param">format</span> <span class="param">format</span>
<span class="param-flags">optional</span> <span class="param-flags">optional</span>
Format for returned data. Can be `pem` or `der`; defaults to `pem`. If Format for returned data. Can be `pem`, `der`, or `pem_bundle`;
`der`, the output is base64 encoded. defaults to `pem`. If `der`, the output is base64 encoded. If
`pem_bundle`, the `csr` field will contain the private key (if
exported) and CSR, concatenated.
</li> </li>
<li> <li>
<span class="param">key_type</span> <span class="param">key_type</span>
@ -860,8 +862,10 @@ subpath for interactive help output.
<li> <li>
<span class="param">format</span> <span class="param">format</span>
<span class="param-flags">optional</span> <span class="param-flags">optional</span>
Format for returned data. Can be `pem` or `der`; defaults to `pem`. If Format for returned data. Can be `pem`, `der`, or `pem_bundle`;
`der`, the output is base64 encoded. defaults to `pem`. If `der`, the output is base64 encoded. If
`pem_bundle`, the `certificate` field will contain the private key,
certificate, and issuing CA, concatenated.
</li> </li>
</ul> </ul>
</dd> </dd>
@ -1233,8 +1237,10 @@ subpath for interactive help output.
<li> <li>
<span class="param">format</span> <span class="param">format</span>
<span class="param-flags">optional</span> <span class="param-flags">optional</span>
Format for returned data. Can be `pem` or `der`; defaults to `pem`. If Format for returned data. Can be `pem`, `der`, or `pem_bundle`;
`der`, the output is base64 encoded. defaults to `pem`. If `der`, the output is base64 encoded. If
`pem_bundle`, the `certificate` field will contain the private key (if exported),
certificate, and issuing CA, concatenated.
</li> </li>
<li> <li>
<span class="param">key_type</span> <span class="param">key_type</span>
@ -1333,8 +1339,10 @@ subpath for interactive help output.
<li> <li>
<span class="param">format</span> <span class="param">format</span>
<span class="param-flags">optional</span> <span class="param-flags">optional</span>
Format for returned data. Can be `pem` or `der`; defaults to `pem`. If Format for returned data. Can be `pem`, `der`, or `pem_bundle`;
`der`, the output is base64 encoded. defaults to `pem`. If `der`, the output is base64 encoded. If
`pem_bundle`, the `certificate` field will contain the certificate and
issuing CA, concatenated.
</li> </li>
<li> <li>
<span class="param">max_path_length</span> <span class="param">max_path_length</span>
@ -1435,8 +1443,10 @@ subpath for interactive help output.
<li> <li>
<span class="param">format</span> <span class="param">format</span>
<span class="param-flags">optional</span> <span class="param-flags">optional</span>
Format for returned data. Can be `pem` or `der`; defaults to `pem`. If Format for returned data. Can be `pem`, `der`, or `pem_bundle`;
`der`, the output is base64 encoded. defaults to `pem`. If `der`, the output is base64 encoded. If
`pem_bundle`, the `certificate` field will contain the certificate and
issuing CA, concatenated.
</li> </li>
</ul> </ul>
</dd> </dd>
@ -1499,8 +1509,10 @@ subpath for interactive help output.
<li> <li>
<span class="param">format</span> <span class="param">format</span>
<span class="param-flags">optional</span> <span class="param-flags">optional</span>
Format for returned data. Can be `pem` or `der`; defaults to `pem`. If Format for returned data. Can be `pem`, `der`, or `pem_bundle`;
`der`, the output is base64 encoded. defaults to `pem`. If `der`, the output is base64 encoded. If
`pem_bundle`, the `certificate` field will contain the certificate and
issuing CA, concatenated.
</li> </li>
</ul> </ul>
</dd> </dd>