80 lines
2 KiB
Go
80 lines
2 KiB
Go
package scep
|
|
|
|
import (
|
|
"crypto/x509"
|
|
"encoding/json"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/smallstep/nosql"
|
|
)
|
|
|
|
type certificate struct {
|
|
ID string `json:"id"`
|
|
Created time.Time `json:"created"`
|
|
Leaf []byte `json:"leaf"`
|
|
Intermediates []byte `json:"intermediates"`
|
|
}
|
|
|
|
// CertOptions options with which to create and store a cert object.
|
|
type CertOptions struct {
|
|
Leaf *x509.Certificate
|
|
Intermediates []*x509.Certificate
|
|
}
|
|
|
|
func newCert(db nosql.DB, ops CertOptions) (*certificate, error) {
|
|
|
|
// TODO: according to the RFC this should be IssuerAndSerialNumber,
|
|
// but sscep seems to use just the serial number for getcert
|
|
|
|
id := ops.Leaf.SerialNumber.String()
|
|
|
|
leaf := pem.EncodeToMemory(&pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: ops.Leaf.Raw,
|
|
})
|
|
var intermediates []byte
|
|
for _, cert := range ops.Intermediates {
|
|
intermediates = append(intermediates, pem.EncodeToMemory(&pem.Block{
|
|
Type: "CERTIFICATE",
|
|
Bytes: cert.Raw,
|
|
})...)
|
|
}
|
|
|
|
cert := &certificate{
|
|
ID: id,
|
|
Leaf: leaf,
|
|
Intermediates: intermediates,
|
|
Created: time.Now().UTC(),
|
|
}
|
|
certB, err := json.Marshal(cert)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: error marshaling certificate", err)
|
|
}
|
|
|
|
_, swapped, err := db.CmpAndSwap(certTable, []byte(id), nil, certB)
|
|
switch {
|
|
case err != nil:
|
|
return nil, fmt.Errorf("%w: error storing certificate", err)
|
|
case !swapped:
|
|
return nil, fmt.Errorf("error storing certificate; " +
|
|
"value has changed since last read")
|
|
default:
|
|
return cert, nil
|
|
}
|
|
}
|
|
|
|
func getCert(db nosql.DB, id string) (*certificate, error) {
|
|
b, err := db.Get(certTable, []byte(id))
|
|
if nosql.IsErrNotFound(err) {
|
|
return nil, fmt.Errorf("certificate %s not found", id)
|
|
} else if err != nil {
|
|
return nil, fmt.Errorf("error loading certificate")
|
|
}
|
|
var cert certificate
|
|
if err := json.Unmarshal(b, &cert); err != nil {
|
|
return nil, fmt.Errorf("%w: error unmarshaling certificate", err)
|
|
}
|
|
return &cert, nil
|
|
}
|