diff --git a/scep.go b/scep.go index d922866..2184fb6 100644 --- a/scep.go +++ b/scep.go @@ -149,7 +149,7 @@ func WithLogger(logger Logger) Option { } // WithCACerts adds option CA certificates to the SCEP operations. -// Note: This changes the verification behavior of PKCS #7 messages. If this +// Note: This changes the verification behavior of PKCS#7 messages. If this // option is specified, only caCerts will be used as expected signers. func WithCACerts(caCerts []*x509.Certificate) Option { return func(c *config) { @@ -161,7 +161,7 @@ func WithCACerts(caCerts []*x509.Certificate) Option { // operations. // This option is effective when used with NewCSRRequest function. In // this case, only certificates selected with the certsSelector will be used -// as the PKCS #7 message recipients. +// as the PKCS#7 message recipients. func WithCertsSelector(selector CertsSelector) Option { return func(c *config) { c.certsSelector = selector @@ -198,7 +198,7 @@ type PKIMessage struct { Recipients []*x509.Certificate // Signer info - SignerKey *rsa.PrivateKey + SignerKey crypto.PrivateKey SignerCert *x509.Certificate logger Logger @@ -247,7 +247,7 @@ func ParsePKIMessage(data []byte, opts ...Option) (*PKIMessage, error) { // signatures have an alternate means of obtaining necessary certificates. // In SCEP case, an alternate means is to use GetCaCert request. // Note: The https://github.com/jscep/jscep implementation logs a warning if - // no certificates were found for signers in the PKCS #7 received from the + // no certificates were found for signers in the PKCS#7 received from the // server, but the certificates obtained from GetCaCert request are still // used for decoding the message. p7.Certificates = conf.caCerts @@ -343,8 +343,22 @@ func (msg *PKIMessage) parseMessageType() error { } } -// DecryptPKIEnvelope decrypts the pkcs envelopedData inside the SCEP PKIMessage -func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key *rsa.PrivateKey) error { +// DecryptPKIEnvelope decrypts the PKCS#7 envelopedData inside the SCEP PKIMessage +func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key crypto.PrivateKey) error { + if cert == nil { + return errors.New("scep: cert must not be nil") + } + if key == nil { + return errors.New("scep: key must not be nil") + } + decrypter, ok := key.(crypto.Decrypter) + if !ok { + return errors.New("scep: private key does not implement crypto.Decrypter") + } + if _, ok := decrypter.Public().(*rsa.PublicKey); !ok { + return fmt.Errorf("scep: key.Public() returned type %T; expected *rsa.PublicKey", decrypter.Public()) + } + p7, err := pkcs7.Parse(msg.p7.Content) if err != nil { return err @@ -393,7 +407,8 @@ func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key *rsa.Priva } } -func (msg *PKIMessage) Fail(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, info FailInfo) (*PKIMessage, error) { +// Fail returns a new PKIMessage with CertRep data indicating a failure +func (msg *PKIMessage) Fail(crtAuth *x509.Certificate, keyAuth crypto.PrivateKey, info FailInfo) (*PKIMessage, error) { config := pkcs7.SignerInfoConfig{ ExtraSignedAttributes: []pkcs7.Attribute{ { @@ -456,9 +471,9 @@ func (msg *PKIMessage) Fail(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, } // Success returns a new PKIMessage with CertRep data using an already-issued certificate -func (msg *PKIMessage) Success(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, crt *x509.Certificate) (*PKIMessage, error) { +func (msg *PKIMessage) Success(crtAuth *x509.Certificate, keyAuth crypto.PrivateKey, crt *x509.Certificate) (*PKIMessage, error) { // check if CSRReqMessage has already been decrypted - if msg.CSRReqMessage.CSR == nil { + if msg.CSRReqMessage.CSR == nil { // TODO(hslatman): remove this; just require decryption before, so that we can make keyAuth a crypto.Signer if err := msg.DecryptPKIEnvelope(crtAuth, keyAuth); err != nil { return nil, err } @@ -538,7 +553,7 @@ func (msg *PKIMessage) Success(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKe return crepMsg, nil } -// DegenerateCertificates creates degenerate certificates pkcs#7 type +// DegenerateCertificates creates degenerate certificates PKCS#7 type func DegenerateCertificates(certs []*x509.Certificate) ([]byte, error) { var buf bytes.Buffer for _, cert := range certs { @@ -551,7 +566,7 @@ func DegenerateCertificates(certs []*x509.Certificate) ([]byte, error) { return degenerate, nil } -// CACerts extract CA Certificate or chain from pkcs7 degenerate signed data +// CACerts extract CA Certificate or chain from PKCS#7 degenerate signed data func CACerts(data []byte) ([]*x509.Certificate, error) { p7, err := pkcs7.Parse(data) if err != nil { diff --git a/scep_test.go b/scep_test.go index 18ea384..cd92a3d 100644 --- a/scep_test.go +++ b/scep_test.go @@ -1,6 +1,7 @@ package scep import ( + "crypto" "crypto/rand" "crypto/rsa" "crypto/x509" @@ -8,6 +9,7 @@ import ( "encoding/pem" "errors" "fmt" + "io" "math/big" "os" "path" @@ -90,6 +92,39 @@ func TestDecryptPKIEnvelopeCSR(t *testing.T) { } } +func TestDecryptPKIEnvelopeDecrypter(t *testing.T) { + pkcsReq := readTestFile(t, "PKCSReq.der") + msg := testParsePKIMessage(t, pkcsReq) + cacert, cakey := loadCACredentials(t) + if err := msg.DecryptPKIEnvelope(nil, cakey); err == nil { + t.Fatal("expected error on nil cert") + } + + if err := msg.DecryptPKIEnvelope(cacert, nil); err == nil { + t.Fatal("expected error on nil key") + } + + if err := msg.DecryptPKIEnvelope(cacert, ¬ADecrypter{}); err == nil { + t.Fatal("expected error on invalid decrypter") + } + + if err := msg.DecryptPKIEnvelope(cacert, &nonRSADecrypter{}); err == nil { + t.Fatal("expected error on non-RSA decrypter") + } +} + +type notADecrypter struct{} + +type nonRSADecrypter struct{} + +func (d *nonRSADecrypter) Public() crypto.PublicKey { + return struct{}{} +} + +func (d *nonRSADecrypter) Decrypt(_ io.Reader, _ []byte, _ crypto.DecrypterOpts) (plaintext []byte, err error) { + return nil, errors.New("not implemented") +} + func TestDecryptPKIEnvelopeCert(t *testing.T) { certRep := readTestFile(t, "CertRep.der") testParsePKIMessage(t, certRep) diff --git a/x509util/x509util.go b/x509util/x509util.go index 0e65409..53f9517 100644 --- a/x509util/x509util.go +++ b/x509util/x509util.go @@ -55,7 +55,7 @@ type CertificateRequest struct { // challengePassword attribute. // // See https://github.com/golang/go/issues/15995 -func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) { +func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv crypto.PrivateKey) (csr []byte, err error) { if template.ChallengePassword == "" { // if no challenge password, return a stdlib CSR. return x509.CreateCertificateRequest(rand, &template.CertificateRequest, priv)