Return revocation info within existing certs/<serial> api (#17774)
* Return revocation info within existing certs/<serial> api - The api already returned both the certificate and a revocation_time field populated. Update the api to return revocation_time_rfc3339 as we do elsewhere and also the issuer id if it was revoked. - This will allow callers to associate a revoked cert with an issuer * Add cl * PR feedback (docs update)
This commit is contained in:
parent
a11f62abf2
commit
550fbdc41c
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/pem"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/vault/sdk/framework"
|
||||
"github.com/hashicorp/vault/sdk/helper/errutil"
|
||||
|
@ -156,6 +157,9 @@ func (b *backend) pathFetchRead(ctx context.Context, req *logical.Request, data
|
|||
var certificate []byte
|
||||
var fullChain []byte
|
||||
var revocationTime int64
|
||||
var revocationIssuerId string
|
||||
var revocationTimeRfc3339 string
|
||||
|
||||
response = &logical.Response{
|
||||
Data: map[string]interface{}{},
|
||||
}
|
||||
|
@ -322,6 +326,11 @@ func (b *backend) pathFetchRead(ctx context.Context, req *logical.Request, data
|
|||
return logical.ErrorResponse(fmt.Sprintf("Error decoding revocation entry for serial %s: %s", serial, err)), nil
|
||||
}
|
||||
revocationTime = revInfo.RevocationTime
|
||||
revocationIssuerId = revInfo.CertificateIssuer.String()
|
||||
|
||||
if !revInfo.RevocationTimeUTC.IsZero() {
|
||||
revocationTimeRfc3339 = revInfo.RevocationTimeUTC.Format(time.RFC3339Nano)
|
||||
}
|
||||
}
|
||||
|
||||
reply:
|
||||
|
@ -354,6 +363,12 @@ reply:
|
|||
default:
|
||||
response.Data["certificate"] = string(certificate)
|
||||
response.Data["revocation_time"] = revocationTime
|
||||
response.Data["revocation_time_rfc3339"] = revocationTimeRfc3339
|
||||
// Only output this field if we have a value for it as it doesn't make sense for a
|
||||
// bunch of code paths that go through here
|
||||
if revocationIssuerId != "" {
|
||||
response.Data["issuer_id"] = revocationIssuerId
|
||||
}
|
||||
|
||||
if len(fullChain) > 0 {
|
||||
response.Data["ca_chain"] = string(fullChain)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package pki
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -63,6 +64,7 @@ func TestAutoTidy(t *testing.T) {
|
|||
require.NotNil(t, resp)
|
||||
require.NotEmpty(t, resp.Data)
|
||||
require.NotEmpty(t, resp.Data["issuer_id"])
|
||||
issuerId := resp.Data["issuer_id"]
|
||||
|
||||
// Run tidy so status is not empty when we run it later...
|
||||
_, err = client.Logical().Write("pki/tidy", map[string]interface{}{
|
||||
|
@ -101,6 +103,17 @@ func TestAutoTidy(t *testing.T) {
|
|||
leafSerial := resp.Data["serial_number"].(string)
|
||||
leafCert := parseCert(t, resp.Data["certificate"].(string))
|
||||
|
||||
// Read cert before revoking
|
||||
resp, err = client.Logical().Read("pki/cert/" + leafSerial)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, resp)
|
||||
require.NotNil(t, resp.Data)
|
||||
require.NotEmpty(t, resp.Data["certificate"])
|
||||
revocationTime, err := (resp.Data["revocation_time"].(json.Number)).Int64()
|
||||
require.Equal(t, int64(0), revocationTime, "revocation time was not zero")
|
||||
require.Empty(t, resp.Data["revocation_time_rfc3339"], "revocation_time_rfc3339 was not empty")
|
||||
require.Empty(t, resp.Data["issuer_id"], "issuer_id was not empty")
|
||||
|
||||
_, err = client.Logical().Write("pki/revoke", map[string]interface{}{
|
||||
"serial_number": leafSerial,
|
||||
})
|
||||
|
@ -112,6 +125,22 @@ func TestAutoTidy(t *testing.T) {
|
|||
require.NotNil(t, resp)
|
||||
require.NotNil(t, resp.Data)
|
||||
require.NotEmpty(t, resp.Data["certificate"])
|
||||
revocationTime, err = (resp.Data["revocation_time"].(json.Number)).Int64()
|
||||
require.NoError(t, err, "failed converting %s to int", resp.Data["revocation_time"])
|
||||
revTime := time.Unix(revocationTime, 0)
|
||||
now := time.Now()
|
||||
if !(now.After(revTime) && now.Add(-10*time.Minute).Before(revTime)) {
|
||||
t.Fatalf("parsed revocation time not within the last 10 minutes current time: %s, revocation time: %s", now, revTime)
|
||||
}
|
||||
utcLoc, err := time.LoadLocation("UTC")
|
||||
require.NoError(t, err, "failed to parse UTC location?")
|
||||
|
||||
rfc3339RevocationTime, err := time.Parse(time.RFC3339Nano, resp.Data["revocation_time_rfc3339"].(string))
|
||||
require.NoError(t, err, "failed parsing revocation_time_rfc3339 field: %s", resp.Data["revocation_time_rfc3339"])
|
||||
|
||||
require.Equal(t, revTime.In(utcLoc), rfc3339RevocationTime.Truncate(time.Second),
|
||||
"revocation times did not match revocation_time: %s, "+"rfc3339 time: %s", revTime, rfc3339RevocationTime)
|
||||
require.Equal(t, issuerId, resp.Data["issuer_id"], "issuer_id on leaf cert did not match")
|
||||
|
||||
// Wait for cert to expire and the safety buffer to elapse.
|
||||
time.Sleep(time.Until(leafCert.NotAfter) + 3*time.Second)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
```release-note:improvement
|
||||
secrets/pki: Return new fields revocation_time_rfc3339 and issuer_id to existing certificate serial lookup api if it is revoked
|
||||
```
|
|
@ -1314,7 +1314,10 @@ $ curl \
|
|||
```json
|
||||
{
|
||||
"data": {
|
||||
"certificate": "-----BEGIN CERTIFICATE-----\nMIIGmDCCBYCgAwIBAgIHBzEB3fTzhTANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE\n..."
|
||||
"certificate": "-----BEGIN CERTIFICATE-----\nMIIGmDCCBYCgAwIBAgIHBzEB3fTzhTANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE\n...",
|
||||
"revocation_time": 1667400107,
|
||||
"revocation_time_rfc3339": "2022-11-02T14:41:47.327515Z",
|
||||
"issuer_id": "e27bf456-51e1-d937-0001-4a609184fd9b"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue