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

Use crypto.PrivateKey instead of *rsa.PrivateKey where possible #14

Merged
merged 4 commits into from
Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
37 changes: 26 additions & 11 deletions scep.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
Expand Down Expand Up @@ -198,7 +198,7 @@ type PKIMessage struct {
Recipients []*x509.Certificate

// Signer info
SignerKey *rsa.PrivateKey
SignerKey crypto.PrivateKey
SignerCert *x509.Certificate

logger Logger
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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{
{
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
35 changes: 35 additions & 0 deletions scep_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package scep

import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"io"
"math/big"
"os"
"path"
Expand Down Expand Up @@ -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, &notADecrypter{}); 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)
Expand Down
2 changes: 1 addition & 1 deletion x509util/x509util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading