Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return revocation info within existing certs/<serial> api #17774

Merged
merged 3 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions builtin/logical/pki/path_fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/pem"
"fmt"
"strings"
"time"

"github.com/hashicorp/vault/sdk/framework"
"github.com/hashicorp/vault/sdk/helper/errutil"
Expand Down Expand Up @@ -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{}{},
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
29 changes: 29 additions & 0 deletions builtin/logical/pki/path_tidy_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pki

import (
"encoding/json"
"testing"
"time"

Expand Down Expand Up @@ -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{}{
Expand Down Expand Up @@ -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,
})
Expand All @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions changelog/17774.txt
Original file line number Diff line number Diff line change
@@ -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
```
17 changes: 16 additions & 1 deletion website/content/api-docs/secret/pki.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,22 @@ $ curl \
```json
{
"data": {
"certificate": "-----BEGIN CERTIFICATE-----\nMIIGmDCCBYCgAwIBAgIHBzEB3fTzhTANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE\n..."
"certificate": "-----BEGIN CERTIFICATE-----\nMIIGmDCCBYCgAwIBAgIHBzEB3fTzhTANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE\n...",
"revocation_time": 0
}
}
```

As of Vault 1.13.0, a revoked certificate may contain two additional fields, `revocation_time_rfc3339` and `issuer_id`
stevendpclark marked this conversation as resolved.
Show resolved Hide resolved
if they are populated in storage.

```json
{
"data": {
"certificate": "-----BEGIN CERTIFICATE-----\nMIIGmDCCBYCgAwIBAgIHBzEB3fTzhTANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UE\n...",
"revocation_time": 1667400107,
"revocation_time_rfc3339": "2022-11-02T14:41:47.327515Z",
"issuer_id": "e27bf456-51e1-d937-0001-4a609184fd9b"
}
}
```
Expand Down