Skip to content

Commit b462566

Browse files
committed
Add certificate fingerprints and validity dates too
1 parent 4e4af28 commit b462566

File tree

3 files changed

+90
-11
lines changed

3 files changed

+90
-11
lines changed

docs/endpoints.md

+10-1
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="som
385385

386386
### Request
387387

388-
Get the public configuration of a configured signer. For example:
388+
Get the sanitized configuration of a signer. For example:
389389

390390
```bash
391391
GET /config/dummyrsa
@@ -410,3 +410,12 @@ Authorization: Hawk id="dh37fgj492je", ts="1353832234", nonce="j4h3g2", ext="som
410410
"hash": "sha256"
411411
}
412412
```
413+
414+
The returned configuration should be a subset of the internal configuration with the following differences:
415+
- Public values, such as the `id`, `publickey` and `certificate` are copied verbatim.
416+
- Private keys are hashed, and return only the SHA256 checksum of the secret value.
417+
- The `certificate`, if present is parsed and the following additional fields are added:
418+
+ `cert_sha1`: Contains the SHA1 fingerprint of the DER certificate.
419+
+ `cert_sha256`: Contains the SHA256 fingerprint of the DER certificate.
420+
+ `cert_start`: Contains the certificate `NotBefore` time in RFC 3339 format.
421+
+ `cert_end`: Contains the certificate `NotAfter` time in RFC 3339 format.

signer/signer.go

+34-10
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ import (
1212
"crypto/elliptic"
1313
"crypto/rand"
1414
"crypto/rsa"
15+
"crypto/sha1"
1516
"crypto/sha256"
1617
"crypto/x509"
1718
"encoding/base64"
1819
"encoding/pem"
1920
"fmt"
21+
"hash"
2022
"io"
2123
"regexp"
2224
"strings"
@@ -186,24 +188,26 @@ type SanitizedConfig struct {
186188
PrivateKey string `json:"privatekey,omitempty" yaml:"privatekey,omitempty"`
187189
IssuerPrivKey string `json:"issuerprivkey,omitempty" yaml:"issuerprivkey,omitempty"`
188190

189-
// TODO: To fully replace the config-sanitizer tool, we should also include
190-
// fingerprints and expiration times of the certificate (if present).
191+
// If a certificate is present, add fingerprints and expiration dates.
192+
CertFingerprintSha1 string `json:"cert_sha1,omitempty" yaml:"cert_sha1,omitempty"`
193+
CertFingerprintSha256 string `json:"cert_sha256,omitempty" yaml:"cert_sha256,omitempty"`
194+
CertDateStart string `json:"cert_date_start,omitempty" yaml:"cert_date_start,omitempty"`
195+
CertDateEnd string `json:"cert_date_end,omitempty" yaml:"cert_date_end,omitempty"`
191196
}
192197

193-
func hashSecretString(secret string) string {
198+
func hashFingerprint(secret []byte, algorithm hash.Hash) string {
194199
// Empty strings should stay empty
195-
if secret == "" {
200+
if len(secret) == 0 {
196201
return ""
197202
}
198203

199-
h := sha256.New()
200-
h.Write([]byte(secret))
201-
return fmt.Sprintf("%x", h.Sum(nil))
204+
algorithm.Write(secret)
205+
return fmt.Sprintf("%x", algorithm.Sum(nil))
202206
}
203207

204208
// Sanitize configuration to make it suitable for public export
205209
func (cfg *Configuration) Sanitize() *SanitizedConfig {
206-
return &SanitizedConfig{
210+
result := &SanitizedConfig{
207211
// Copy public values verbatim.
208212
ID: cfg.ID,
209213
Type: cfg.Type,
@@ -222,9 +226,29 @@ func (cfg *Configuration) Sanitize() *SanitizedConfig {
222226
SaltLength: cfg.SaltLength,
223227

224228
// Hash private keys, if present.
225-
PrivateKey: hashSecretString(cfg.PrivateKey),
226-
IssuerPrivKey: hashSecretString(cfg.IssuerPrivKey),
229+
PrivateKey: hashFingerprint([]byte(cfg.PrivateKey), sha256.New()),
230+
IssuerPrivKey: hashFingerprint([]byte(cfg.IssuerPrivKey), sha256.New()),
231+
}
232+
233+
// If a certificate exists - parse it.
234+
certDER, _ := pem.Decode([]byte(cfg.Certificate))
235+
if certDER != nil && certDER.Type == "CERTIFICATE" {
236+
certX509, err := x509.ParseCertificate(certDER.Bytes)
237+
if err == nil {
238+
result.CertFingerprintSha1 = hashFingerprint(certDER.Bytes, sha1.New())
239+
result.CertFingerprintSha256 = hashFingerprint(certDER.Bytes, sha256.New())
240+
start, err := certX509.NotBefore.MarshalText()
241+
if err == nil {
242+
result.CertDateStart = string(start)
243+
}
244+
end, err := certX509.NotAfter.MarshalText()
245+
if err == nil {
246+
result.CertDateEnd = string(end)
247+
}
248+
}
227249
}
250+
251+
return result
228252
}
229253

230254
// InitHSM indicates that an HSM has been initialized

signer/signer_test.go

+46
Original file line numberDiff line numberDiff line change
@@ -373,4 +373,50 @@ var sanitizerTestCases = []struct {
373373
// echo -n "Lorem Ipsum" | sha256sum
374374
IssuerPrivKey: "030dc1f936c3415aff3f3357163515190d347a28e758e1f717d17bae453541c9",
375375
}},
376+
// Certificates should parse out the fingerprint and validity dates.
377+
{cfg: Configuration{
378+
ID: "cert-extra-data",
379+
Certificate: `
380+
-----BEGIN CERTIFICATE-----
381+
MIICXDCCAeKgAwIBAgIIFYW6xg9HrnAwCgYIKoZIzj0EAwMwXzELMAkGA1UEBhMC
382+
VVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRAwDgYDVQQK
383+
EwdNb3ppbGxhMRkwFwYDVQQDExBjc3Jvb3QxNTUwODUxMDA2MB4XDTE4MTIyMTE1
384+
NTY0NloXDTI5MDIyMjE1NTY0NlowYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB
385+
MRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKEwdNb3ppbGxhMRowGAYD
386+
VQQDExFjc2ludGVyMTU1MDg1MTAwNjB2MBAGByqGSM49AgEGBSuBBAAiA2IABAwF
387+
9wOPiv/1oBdxSyOO6fe8KkFJCiyRx2KIXhsT4BwWY8AGHoCfBNm/Swdg+OSi+TdH
388+
dF+5eUrKiqG4PvdWoGGS4rtHqY3ayeF9GRaaLpLMdZkhc/MVJygJoecmsXM2O6Nq
389+
MGgwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA8GA1UdEwEB
390+
/wQFMAMBAf8wMAYDVR0eAQH/BCYwJKAiMCCCHi5jb250ZW50LXNpZ25hdHVyZS5t
391+
b3ppbGxhLm9yZzAKBggqhkjOPQQDAwNoADBlAjBss+GLdMdLT2Y/g73OE9x0WyUG
392+
vqzO7klt20yytmhaYMIPT/zRnWsHZbqEijHMzGsCMQDEoKetuWkyBkzAytS6l+ss
393+
mYigBlwySY+gTqsjuIrydWlKaOv1GU+PXbwX0cQuaN8=
394+
-----END CERTIFICATE-----`,
395+
},
396+
result: SanitizedConfig{
397+
ID: "cert-extra-data",
398+
Certificate: `
399+
-----BEGIN CERTIFICATE-----
400+
MIICXDCCAeKgAwIBAgIIFYW6xg9HrnAwCgYIKoZIzj0EAwMwXzELMAkGA1UEBhMC
401+
VVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRAwDgYDVQQK
402+
EwdNb3ppbGxhMRkwFwYDVQQDExBjc3Jvb3QxNTUwODUxMDA2MB4XDTE4MTIyMTE1
403+
NTY0NloXDTI5MDIyMjE1NTY0NlowYDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB
404+
MRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKEwdNb3ppbGxhMRowGAYD
405+
VQQDExFjc2ludGVyMTU1MDg1MTAwNjB2MBAGByqGSM49AgEGBSuBBAAiA2IABAwF
406+
9wOPiv/1oBdxSyOO6fe8KkFJCiyRx2KIXhsT4BwWY8AGHoCfBNm/Swdg+OSi+TdH
407+
dF+5eUrKiqG4PvdWoGGS4rtHqY3ayeF9GRaaLpLMdZkhc/MVJygJoecmsXM2O6Nq
408+
MGgwDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA8GA1UdEwEB
409+
/wQFMAMBAf8wMAYDVR0eAQH/BCYwJKAiMCCCHi5jb250ZW50LXNpZ25hdHVyZS5t
410+
b3ppbGxhLm9yZzAKBggqhkjOPQQDAwNoADBlAjBss+GLdMdLT2Y/g73OE9x0WyUG
411+
vqzO7klt20yytmhaYMIPT/zRnWsHZbqEijHMzGsCMQDEoKetuWkyBkzAytS6l+ss
412+
mYigBlwySY+gTqsjuIrydWlKaOv1GU+PXbwX0cQuaN8=
413+
-----END CERTIFICATE-----`,
414+
// openssl x509 -outform DER | shasum
415+
CertFingerprintSha1: "793a92cb335c3846ffed7f8c112137cd8a75e7c7",
416+
// openssl x509 -outform DER | sha256sum
417+
CertFingerprintSha256: "61bd2500b732d2889a1b17c24365741550534fb715cd4f7c463a23a35bd931ee",
418+
// openssl x509 -noout -text
419+
CertDateStart: "2018-12-21T15:56:46Z",
420+
CertDateEnd: "2029-02-22T15:56:46Z",
421+
}},
376422
}

0 commit comments

Comments
 (0)