diff --git a/README.md b/README.md index a4fb7ed..0f765b0 100644 --- a/README.md +++ b/README.md @@ -175,58 +175,6 @@ docker run -it --rm -v /path/to/ca/folder:/depot micromdm/scep:latest ca -init docker run -it --rm -v /path/to/ca/folder:/depot -p 8080:8080 micromdm/scep:latest ``` -## SCEP library - -The core `scep` library can be used for both client and server operations. - -``` -go get github.com/micromdm/scep/scep -``` - -For detailed usage, see the [Go Reference](https://pkg.go.dev/github.com/micromdm/scep/v2/scep). - -Example (server): - -```go -// read a request body containing SCEP message -body, err := ioutil.ReadAll(r.Body) -if err != nil { - // handle err -} - -// parse the SCEP message -msg, err := scep.ParsePKIMessage(body) -if err != nil { - // handle err -} - -// do something with msg -fmt.Println(msg.MessageType) - -// extract encrypted pkiEnvelope -err := msg.DecryptPKIEnvelope(CAcert, CAkey) -if err != nil { - // handle err -} - -// use the CSR from decrypted PKCS request and sign -// MyCSRSigner returns an *x509.Certificate here -crt, err := MyCSRSigner(msg.CSRReqMessage.CSR) -if err != nil { - // handle err -} - -// create a CertRep message from the original -certRep, err := msg.Success(CAcert, CAkey, crt) -if err != nil { - // handle err -} - -// send response back -// w is a http.ResponseWriter -w.Write(certRep.Raw) -``` - ## Server library You can import the scep endpoint into another Go project. For an example take a look at [scepserver.go](cmd/scepserver/scepserver.go). diff --git a/challenge/challenge.go b/challenge/challenge.go index c5cd56d..6985963 100644 --- a/challenge/challenge.go +++ b/challenge/challenge.go @@ -6,8 +6,9 @@ import ( "crypto/x509" "errors" - "github.com/micromdm/scep/v2/scep" scepserver "github.com/micromdm/scep/v2/server" + + "github.com/smallstep/scep" ) // Validator validates challenge passwords. diff --git a/challenge/challenge_bolt_test.go b/challenge/challenge_bolt_test.go index 1a34cb5..281d6f2 100644 --- a/challenge/challenge_bolt_test.go +++ b/challenge/challenge_bolt_test.go @@ -7,10 +7,10 @@ import ( "testing" challengestore "github.com/micromdm/scep/v2/challenge/bolt" - "github.com/micromdm/scep/v2/scep" scepserver "github.com/micromdm/scep/v2/server" "github.com/boltdb/bolt" + "github.com/smallstep/scep" ) func TestDynamicChallenge(t *testing.T) { diff --git a/cmd/scepclient/scepclient.go b/cmd/scepclient/scepclient.go index 3cfe22d..b54ffa7 100644 --- a/cmd/scepclient/scepclient.go +++ b/cmd/scepclient/scepclient.go @@ -17,11 +17,11 @@ import ( "time" scepclient "github.com/micromdm/scep/v2/client" - "github.com/micromdm/scep/v2/scep" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/pkg/errors" + "github.com/smallstep/scep" ) // version info diff --git a/csrverifier/csrverifier.go b/csrverifier/csrverifier.go index da6f5aa..ef4ae20 100644 --- a/csrverifier/csrverifier.go +++ b/csrverifier/csrverifier.go @@ -6,8 +6,8 @@ import ( "crypto/x509" "errors" - "github.com/micromdm/scep/v2/scep" scepserver "github.com/micromdm/scep/v2/server" + "github.com/smallstep/scep" ) // CSRVerifier verifies the raw decrypted CSR. diff --git a/depot/signer.go b/depot/signer.go index 3e3bdb5..cba19da 100644 --- a/depot/signer.go +++ b/depot/signer.go @@ -6,7 +6,7 @@ import ( "time" "github.com/micromdm/scep/v2/cryptoutil" - "github.com/micromdm/scep/v2/scep" + "github.com/smallstep/scep" ) // Signer signs x509 certificates and stores them in a Depot diff --git a/go.mod b/go.mod index cb5532b..50e08dc 100644 --- a/go.mod +++ b/go.mod @@ -5,13 +5,11 @@ go 1.16 require ( github.com/boltdb/bolt v1.3.1 github.com/go-kit/kit v0.4.0 - github.com/go-logfmt/logfmt v0.3.0 // indirect - github.com/go-stack/stack v1.6.0 // indirect github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f // indirect github.com/gorilla/mux v1.4.0 github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda - github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 // indirect github.com/pkg/errors v0.8.0 - github.com/smallstep/pkcs7 v0.0.0-20231107075624-be1870d87d13 + github.com/smallstep/pkcs7 v0.0.0-20231107075624-be1870d87d13 // indirect + github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99 golang.org/x/net v0.23.0 // indirect ) diff --git a/go.sum b/go.sum index 82b79cb..38f66b1 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/go-kit/kit v0.4.0 h1:KeVK+Emj3c3S4eRztFuzbFYb2BAgf2jmwDwyXEri7Lo= github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0 h1:8HUsc87TaSWLKwrnumgC8/YconD2fJQsRJAsWaPg2ic= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-stack/stack v1.6.0 h1:MmJCxYVKTJ0SplGKqFVX3SBnmaUhODHZrrFF6jMbpZk= github.com/go-stack/stack v1.6.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f h1:9oNbS1z4rVpbnkHBdPZU4jo9bSmrLpII768arSyMFgk= @@ -12,12 +12,13 @@ github.com/gorilla/mux v1.4.0 h1:N6R8isjoRv7IcVVlf0cTBbo0UDc9V6ZXWEm0HQoQmLo= github.com/gorilla/mux v1.4.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda h1:5ikpG9mYCMFiZX0nkxoV6aU2IpCHPdws3gCNgdZeEV0= github.com/groob/finalizer v0.0.0-20170707115354-4c2ed49aabda/go.mod h1:MyndkAZd5rUMdNogn35MWXBX1UiBigrU8eTj8DoAC2c= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/smallstep/pkcs7 v0.0.0-20231024181729-3b98ecc1ca81/go.mod h1:SoUAr/4M46rZ3WaLstHxGhLEgoYIDRqxQEXLOmOEB0Y= github.com/smallstep/pkcs7 v0.0.0-20231107075624-be1870d87d13 h1:qRxEt9ESQhAg1kjmgJ8oyyzlc9zkAjOooe7bcKjKORQ= github.com/smallstep/pkcs7 v0.0.0-20231107075624-be1870d87d13/go.mod h1:SoUAr/4M46rZ3WaLstHxGhLEgoYIDRqxQEXLOmOEB0Y= +github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99 h1:e85HuLX5/MW15yJ7yWb/PMNFW1Kx1N+DeQtpQnlMUbw= +github.com/smallstep/scep v0.0.0-20240214080410-892e41795b99/go.mod h1:4d0ub42ut1mMtvGyMensjuHYEUpRrASvkzLEJvoRQcU= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= diff --git a/scep/certs_selector.go b/scep/certs_selector.go deleted file mode 100644 index 62d726d..0000000 --- a/scep/certs_selector.go +++ /dev/null @@ -1,57 +0,0 @@ -package scep - -import ( - "bytes" - "crypto" - "crypto/x509" -) - -// A CertsSelector filters certificates. -type CertsSelector interface { - SelectCerts([]*x509.Certificate) []*x509.Certificate -} - -// CertsSelectorFunc is a type of function that filters certificates. -type CertsSelectorFunc func([]*x509.Certificate) []*x509.Certificate - -func (f CertsSelectorFunc) SelectCerts(certs []*x509.Certificate) []*x509.Certificate { - return f(certs) -} - -// NopCertsSelector returns a CertsSelectorFunc that does not do anything. -func NopCertsSelector() CertsSelectorFunc { - return func(certs []*x509.Certificate) []*x509.Certificate { - return certs - } -} - -// A EnciphermentCertsSelector returns a CertsSelectorFunc that selects -// certificates eligible for key encipherment. This certsSelector can be used -// to filter PKCSReq recipients. -func EnciphermentCertsSelector() CertsSelectorFunc { - return func(certs []*x509.Certificate) (selected []*x509.Certificate) { - enciphermentKeyUsages := x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment - for _, cert := range certs { - if cert.KeyUsage&enciphermentKeyUsages != 0 { - selected = append(selected, cert) - } - } - return selected - } -} - -// FingerprintCertsSelector selects a certificate that matches hash using -// hashType against the digest of the raw certificate DER bytes -func FingerprintCertsSelector(hashType crypto.Hash, hash []byte) CertsSelectorFunc { - return func(certs []*x509.Certificate) (selected []*x509.Certificate) { - for _, cert := range certs { - h := hashType.New() - h.Write(cert.Raw) - if bytes.Compare(hash, h.Sum(nil)) == 0 { - selected = append(selected, cert) - return - } - } - return - } -} diff --git a/scep/certs_selector_test.go b/scep/certs_selector_test.go deleted file mode 100644 index 643249a..0000000 --- a/scep/certs_selector_test.go +++ /dev/null @@ -1,156 +0,0 @@ -package scep - -import ( - "crypto" - _ "crypto/sha256" - "crypto/x509" - "encoding/hex" - "testing" -) - -func TestFingerprintCertsSelector(t *testing.T) { - for _, test := range []struct { - testName string - hashType crypto.Hash - hash string - certRaw []byte - expectedCount int - }{ - { - "null SHA-256 hash", - crypto.SHA256, - "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - nil, - 1, - }, - { - "3 byte SHA-256 hash", - crypto.SHA256, - "039058c6f2c0cb492c533b0a4d14ef77cc0f78abccced5287d84a1a2011cfb81", - []byte{1, 2, 3}, - 1, - }, - { - "mismatched hash", - crypto.SHA256, - "8db07061ebb4cd0b0cd00825b363e5fb7f8131d8ff2c1fd70d03fa4fd6dc3785", - []byte{4, 5, 6}, - 0, - }, - } { - test := test - t.Run(test.testName, func(t *testing.T) { - t.Parallel() - - fakeCerts := []*x509.Certificate{{Raw: test.certRaw}} - - hash, err := hex.DecodeString(test.hash) - if err != nil { - t.Fatal(err) - } - if want, have := test.hashType.Size(), len(hash); want != have { - t.Errorf("invalid input hash length, want: %d have: %d", want, have) - } - - selected := FingerprintCertsSelector(test.hashType, hash).SelectCerts(fakeCerts) - - if want, have := test.expectedCount, len(selected); want != have { - t.Errorf("wrong selected certs count, want: %d have: %d", want, have) - } - }) - } -} - -func TestEnciphermentCertsSelector(t *testing.T) { - for _, test := range []struct { - testName string - certs []*x509.Certificate - expectedSelectedCerts []*x509.Certificate - }{ - { - "empty certificates list", - []*x509.Certificate{}, - []*x509.Certificate{}, - }, - { - "non-empty certificates list", - []*x509.Certificate{ - {KeyUsage: x509.KeyUsageKeyEncipherment}, - {KeyUsage: x509.KeyUsageDataEncipherment}, - {KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment}, - {KeyUsage: x509.KeyUsageDigitalSignature}, - {}, - }, - []*x509.Certificate{ - {KeyUsage: x509.KeyUsageKeyEncipherment}, - {KeyUsage: x509.KeyUsageDataEncipherment}, - {KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment}, - }, - }, - } { - test := test - t.Run(test.testName, func(t *testing.T) { - t.Parallel() - - selected := EnciphermentCertsSelector().SelectCerts(test.certs) - if !certsKeyUsagesEq(selected, test.expectedSelectedCerts) { - t.Fatal("selected and expected certificates did not match") - } - }) - } -} - -func TestNopCertsSelector(t *testing.T) { - for _, test := range []struct { - testName string - certs []*x509.Certificate - expectedSelectedCerts []*x509.Certificate - }{ - { - "empty certificates list", - []*x509.Certificate{}, - []*x509.Certificate{}, - }, - { - "non-empty certificates list", - []*x509.Certificate{ - {KeyUsage: x509.KeyUsageKeyEncipherment}, - {KeyUsage: x509.KeyUsageDataEncipherment}, - {KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment}, - {KeyUsage: x509.KeyUsageDigitalSignature}, - {}, - }, - []*x509.Certificate{ - {KeyUsage: x509.KeyUsageKeyEncipherment}, - {KeyUsage: x509.KeyUsageDataEncipherment}, - {KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment}, - {KeyUsage: x509.KeyUsageDigitalSignature}, - {}, - }, - }, - } { - test := test - t.Run(test.testName, func(t *testing.T) { - t.Parallel() - - selected := NopCertsSelector().SelectCerts(test.certs) - if !certsKeyUsagesEq(selected, test.expectedSelectedCerts) { - t.Fatal("selected and expected certificates did not match") - } - }) - } -} - -// certsKeyUsagesEq returns true if certs in a have the same key usages -// of certs in b and in the same order. -func certsKeyUsagesEq(a []*x509.Certificate, b []*x509.Certificate) bool { - if len(a) != len(b) { - return false - } - for i, cert := range a { - if cert.KeyUsage != b[i].KeyUsage { - return false - } - } - return true -} diff --git a/scep/scep.go b/scep/scep.go deleted file mode 100644 index 8c81615..0000000 --- a/scep/scep.go +++ /dev/null @@ -1,665 +0,0 @@ -// Package scep provides common functionality for encoding and decoding -// Simple Certificate Enrolment Protocol pki messages as defined by -// https://tools.ietf.org/html/draft-gutmann-scep-02 -package scep - -import ( - "bytes" - "crypto" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "encoding/asn1" - "encoding/base64" - - "github.com/micromdm/scep/v2/cryptoutil" - "github.com/micromdm/scep/v2/cryptoutil/x509util" - - "github.com/go-kit/kit/log" - "github.com/go-kit/kit/log/level" - "github.com/pkg/errors" - "github.com/smallstep/pkcs7" -) - -// errors -var ( - errNotImplemented = errors.New("not implemented") - errUnknownMessageType = errors.New("unknown messageType") -) - -// The MessageType attribute specifies the type of operation performed -// by the transaction. This attribute MUST be included in all PKI -// messages. -// -// The following message types are defined: -type MessageType string - -// Undefined message types are treated as an error. -const ( - CertRep MessageType = "3" - RenewalReq = "17" - UpdateReq = "18" - PKCSReq = "19" - CertPoll = "20" - GetCert = "21" - GetCRL = "22" -) - -func (msg MessageType) String() string { - switch msg { - case CertRep: - return "CertRep (3)" - case RenewalReq: - return "RenewalReq (17)" - case UpdateReq: - return "UpdateReq (18)" - case PKCSReq: - return "PKCSReq (19)" - case CertPoll: - return "CertPoll (20) " - case GetCert: - return "GetCert (21)" - case GetCRL: - return "GetCRL (22)" - default: - panic("scep: unknown messageType" + msg) - } -} - -// PKIStatus is a SCEP pkiStatus attribute which holds transaction status information. -// All SCEP responses MUST include a pkiStatus. -// -// The following pkiStatuses are defined: -type PKIStatus string - -// Undefined pkiStatus attributes are treated as an error -const ( - SUCCESS PKIStatus = "0" - FAILURE = "2" - PENDING = "3" -) - -// FailInfo is a SCEP failInfo attribute -// -// The FailInfo attribute MUST contain one of the following failure -// reasons: -type FailInfo string - -const ( - BadAlg FailInfo = "0" - BadMessageCheck = "1" - BadRequest = "2" - BadTime = "3" - BadCertID = "4" -) - -func (info FailInfo) String() string { - switch info { - case BadAlg: - return "badAlg (0)" - case BadMessageCheck: - return "badMessageCheck (1)" - case BadRequest: - return "badRequest (2)" - case BadTime: - return "badTime (3)" - case BadCertID: - return "badCertID (4)" - default: - panic("scep: unknown failInfo type" + info) - } -} - -// SenderNonce is a random 16 byte number. -// A sender must include the senderNonce in each transaction to a recipient. -type SenderNonce []byte - -// The RecipientNonce MUST be copied from the SenderNonce -// and included in the reply. -type RecipientNonce []byte - -// The TransactionID is a text -// string generated by the client when starting a transaction. The -// client MUST generate a unique string as the transaction identifier, -// which MUST be used for all PKI messages exchanged for a given -// enrolment, encoded as a PrintableString. -type TransactionID string - -// SCEP OIDs -var ( - oidSCEPmessageType = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 2} - oidSCEPpkiStatus = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 3} - oidSCEPfailInfo = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 4} - oidSCEPsenderNonce = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 5} - oidSCEPrecipientNonce = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 6} - oidSCEPtransactionID = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 7} -) - -// WithLogger adds option logging to the SCEP operations. -func WithLogger(logger log.Logger) Option { - return func(c *config) { - c.logger = logger - } -} - -// WithCACerts adds option CA certificates to the SCEP operations. -// 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) { - c.caCerts = caCerts - } -} - -// WithCertsSelector adds the certificates certsSelector option to the SCEP -// 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. -func WithCertsSelector(selector CertsSelector) Option { - return func(c *config) { - c.certsSelector = selector - } -} - -// Option specifies custom configuration for SCEP. -type Option func(*config) - -type config struct { - logger log.Logger - caCerts []*x509.Certificate // specified if CA certificates have already been retrieved - certsSelector CertsSelector -} - -// PKIMessage defines the possible SCEP message types -type PKIMessage struct { - TransactionID - MessageType - SenderNonce - *CertRepMessage - *CSRReqMessage - - // DER Encoded PKIMessage - Raw []byte - - // parsed - p7 *pkcs7.PKCS7 - - // decrypted enveloped content - pkiEnvelope []byte - - // Used to encrypt message - Recipients []*x509.Certificate - - // Signer info - SignerKey *rsa.PrivateKey - SignerCert *x509.Certificate - - logger log.Logger -} - -// CertRepMessage is a type of PKIMessage -type CertRepMessage struct { - PKIStatus - RecipientNonce - FailInfo - - Certificate *x509.Certificate - - degenerate []byte -} - -// CSRReqMessage can be of the type PKCSReq/RenewalReq/UpdateReq -// and includes a PKCS#10 CSR request. -// The content of this message is protected -// by the recipient public key(example CA) -type CSRReqMessage struct { - RawDecrypted []byte - - // PKCS#10 Certificate request inside the envelope - CSR *x509.CertificateRequest - - ChallengePassword string -} - -// ParsePKIMessage unmarshals a PKCS#7 signed data into a PKI message struct -func ParsePKIMessage(data []byte, opts ...Option) (*PKIMessage, error) { - conf := &config{logger: log.NewNopLogger()} - for _, opt := range opts { - opt(conf) - } - - // parse PKCS#7 signed data - p7, err := pkcs7.Parse(data) - if err != nil { - return nil, err - } - - if len(conf.caCerts) > 0 { - // According to RFC #2315 Section 9.1, it is valid that the server sends fewer - // certificates than necessary, if it is expected that those verifying the - // 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 - // server, but the certificates obtained from GetCaCert request are still - // used for decoding the message. - p7.Certificates = conf.caCerts - } - - if err := p7.Verify(); err != nil { - return nil, err - } - - var tID TransactionID - if err := p7.UnmarshalSignedAttribute(oidSCEPtransactionID, &tID); err != nil { - return nil, err - } - - var msgType MessageType - if err := p7.UnmarshalSignedAttribute(oidSCEPmessageType, &msgType); err != nil { - return nil, err - } - - msg := &PKIMessage{ - TransactionID: tID, - MessageType: msgType, - Raw: data, - p7: p7, - logger: conf.logger, - } - - // log relevant key-values when parsing a pkiMessage. - logKeyVals := []interface{}{ - "msg", "parsed scep pkiMessage", - "scep_message_type", msgType, - "transaction_id", tID, - } - level.Debug(msg.logger).Log(logKeyVals...) - - if err := msg.parseMessageType(); err != nil { - return nil, err - } - - return msg, nil -} - -func (msg *PKIMessage) parseMessageType() error { - switch msg.MessageType { - case CertRep: - var status PKIStatus - if err := msg.p7.UnmarshalSignedAttribute(oidSCEPpkiStatus, &status); err != nil { - return err - } - var rn RecipientNonce - if err := msg.p7.UnmarshalSignedAttribute(oidSCEPrecipientNonce, &rn); err != nil { - return err - } - if len(rn) == 0 { - return errors.New("scep pkiMessage must include recipientNonce attribute") - } - cr := &CertRepMessage{ - PKIStatus: status, - RecipientNonce: rn, - } - switch status { - case SUCCESS: - break - case FAILURE: - var fi FailInfo - if err := msg.p7.UnmarshalSignedAttribute(oidSCEPfailInfo, &fi); err != nil { - return err - } - if fi == "" { - return errors.New("scep pkiStatus FAILURE must have a failInfo attribute") - } - cr.FailInfo = fi - case PENDING: - break - default: - return errors.Errorf("unknown scep pkiStatus %s", status) - } - msg.CertRepMessage = cr - return nil - case PKCSReq, UpdateReq, RenewalReq: - var sn SenderNonce - if err := msg.p7.UnmarshalSignedAttribute(oidSCEPsenderNonce, &sn); err != nil { - return err - } - if len(sn) == 0 { - return errors.New("scep pkiMessage must include senderNonce attribute") - } - msg.SenderNonce = sn - return nil - case GetCRL, GetCert, CertPoll: - return errNotImplemented - default: - return errUnknownMessageType - } -} - -// DecryptPKIEnvelope decrypts the pkcs envelopedData inside the SCEP PKIMessage -func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key *rsa.PrivateKey) error { - p7, err := pkcs7.Parse(msg.p7.Content) - if err != nil { - return err - } - msg.pkiEnvelope, err = p7.Decrypt(cert, key) - if err != nil { - return err - } - - logKeyVals := []interface{}{ - "msg", "decrypt pkiEnvelope", - } - defer func() { level.Debug(msg.logger).Log(logKeyVals...) }() - - switch msg.MessageType { - case CertRep: - certs, err := CACerts(msg.pkiEnvelope) - if err != nil { - return err - } - msg.CertRepMessage.Certificate = certs[0] - logKeyVals = append(logKeyVals, "ca_certs", len(certs)) - return nil - case PKCSReq, UpdateReq, RenewalReq: - csr, err := x509.ParseCertificateRequest(msg.pkiEnvelope) - if err != nil { - return errors.Wrap(err, "parse CSR from pkiEnvelope") - } - // check for challengePassword - cp, err := x509util.ParseChallengePassword(msg.pkiEnvelope) - if err != nil { - return errors.Wrap(err, "scep: parse challenge password in pkiEnvelope") - } - msg.CSRReqMessage = &CSRReqMessage{ - RawDecrypted: msg.pkiEnvelope, - CSR: csr, - ChallengePassword: cp, - } - logKeyVals = append(logKeyVals, "has_challenge", cp != "") - return nil - case GetCRL, GetCert, CertPoll: - return errNotImplemented - default: - return errUnknownMessageType - } -} - -func (msg *PKIMessage) Fail(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, info FailInfo) (*PKIMessage, error) { - config := pkcs7.SignerInfoConfig{ - ExtraSignedAttributes: []pkcs7.Attribute{ - { - Type: oidSCEPtransactionID, - Value: msg.TransactionID, - }, - { - Type: oidSCEPpkiStatus, - Value: FAILURE, - }, - { - Type: oidSCEPfailInfo, - Value: info, - }, - { - Type: oidSCEPmessageType, - Value: CertRep, - }, - { - Type: oidSCEPsenderNonce, - Value: msg.SenderNonce, - }, - { - Type: oidSCEPrecipientNonce, - Value: msg.SenderNonce, - }, - }, - } - - sd, err := pkcs7.NewSignedData(nil) - if err != nil { - return nil, err - } - - // sign the attributes - if err := sd.AddSigner(crtAuth, keyAuth, config); err != nil { - return nil, err - } - - certRepBytes, err := sd.Finish() - if err != nil { - return nil, err - } - - cr := &CertRepMessage{ - PKIStatus: FAILURE, - FailInfo: BadRequest, - RecipientNonce: RecipientNonce(msg.SenderNonce), - } - - // create a CertRep message from the original - crepMsg := &PKIMessage{ - Raw: certRepBytes, - TransactionID: msg.TransactionID, - MessageType: CertRep, - CertRepMessage: cr, - } - - return crepMsg, nil - -} - -// 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) { - // check if CSRReqMessage has already been decrypted - if msg.CSRReqMessage.CSR == nil { - if err := msg.DecryptPKIEnvelope(crtAuth, keyAuth); err != nil { - return nil, err - } - } - - // create a degenerate cert structure - deg, err := DegenerateCertificates([]*x509.Certificate{crt}) - if err != nil { - return nil, err - } - - // encrypt degenerate data using the original messages recipients - e7, err := pkcs7.Encrypt(deg, msg.p7.Certificates) - if err != nil { - return nil, err - } - - // PKIMessageAttributes to be signed - config := pkcs7.SignerInfoConfig{ - ExtraSignedAttributes: []pkcs7.Attribute{ - { - Type: oidSCEPtransactionID, - Value: msg.TransactionID, - }, - { - Type: oidSCEPpkiStatus, - Value: SUCCESS, - }, - { - Type: oidSCEPmessageType, - Value: CertRep, - }, - { - Type: oidSCEPsenderNonce, - Value: msg.SenderNonce, - }, - { - Type: oidSCEPrecipientNonce, - Value: msg.SenderNonce, - }, - }, - } - - signedData, err := pkcs7.NewSignedData(e7) - if err != nil { - return nil, err - } - // add the certificate into the signed data type - // this cert must be added before the signedData because the recipient will expect it - // as the first certificate in the array - signedData.AddCertificate(crt) - // sign the attributes - if err := signedData.AddSigner(crtAuth, keyAuth, config); err != nil { - return nil, err - } - - certRepBytes, err := signedData.Finish() - if err != nil { - return nil, err - } - - cr := &CertRepMessage{ - PKIStatus: SUCCESS, - RecipientNonce: RecipientNonce(msg.SenderNonce), - Certificate: crt, - degenerate: deg, - } - - // create a CertRep message from the original - crepMsg := &PKIMessage{ - Raw: certRepBytes, - TransactionID: msg.TransactionID, - MessageType: CertRep, - CertRepMessage: cr, - } - - return crepMsg, nil -} - -// DegenerateCertificates creates degenerate certificates pkcs#7 type -func DegenerateCertificates(certs []*x509.Certificate) ([]byte, error) { - var buf bytes.Buffer - for _, cert := range certs { - buf.Write(cert.Raw) - } - degenerate, err := pkcs7.DegenerateCertificate(buf.Bytes()) - if err != nil { - return nil, err - } - return degenerate, nil -} - -// CACerts extract CA Certificate or chain from pkcs7 degenerate signed data -func CACerts(data []byte) ([]*x509.Certificate, error) { - p7, err := pkcs7.Parse(data) - if err != nil { - return nil, err - } - return p7.Certificates, nil -} - -// NewCSRRequest creates a scep PKI PKCSReq/UpdateReq message -func NewCSRRequest(csr *x509.CertificateRequest, tmpl *PKIMessage, opts ...Option) (*PKIMessage, error) { - conf := &config{logger: log.NewNopLogger(), certsSelector: NopCertsSelector()} - for _, opt := range opts { - opt(conf) - } - - derBytes := csr.Raw - recipients := conf.certsSelector.SelectCerts(tmpl.Recipients) - if len(recipients) < 1 { - if len(tmpl.Recipients) >= 1 { - // our certsSelector eliminated any CA/RA recipients - return nil, errors.New("no selected CA/RA recipients") - } - return nil, errors.New("no CA/RA recipients") - } - e7, err := pkcs7.Encrypt(derBytes, recipients) - if err != nil { - return nil, err - } - - signedData, err := pkcs7.NewSignedData(e7) - if err != nil { - return nil, err - } - - // create transaction ID from public key hash - tID, err := newTransactionID(csr.PublicKey) - if err != nil { - return nil, err - } - - sn, err := newNonce() - if err != nil { - return nil, err - } - - level.Debug(conf.logger).Log( - "msg", "creating SCEP CSR request", - "transaction_id", tID, - "signer_cn", tmpl.SignerCert.Subject.CommonName, - ) - - // PKIMessageAttributes to be signed - config := pkcs7.SignerInfoConfig{ - ExtraSignedAttributes: []pkcs7.Attribute{ - { - Type: oidSCEPtransactionID, - Value: tID, - }, - { - Type: oidSCEPmessageType, - Value: tmpl.MessageType, - }, - { - Type: oidSCEPsenderNonce, - Value: sn, - }, - }, - } - - // sign attributes - if err := signedData.AddSigner(tmpl.SignerCert, tmpl.SignerKey, config); err != nil { - return nil, err - } - - rawPKIMessage, err := signedData.Finish() - if err != nil { - return nil, err - } - - cr := &CSRReqMessage{ - CSR: csr, - } - - newMsg := &PKIMessage{ - Raw: rawPKIMessage, - MessageType: tmpl.MessageType, - TransactionID: tID, - SenderNonce: sn, - CSRReqMessage: cr, - Recipients: recipients, - logger: conf.logger, - } - - return newMsg, nil -} - -func newNonce() (SenderNonce, error) { - size := 16 - b := make([]byte, size) - _, err := rand.Read(b) - if err != nil { - return SenderNonce{}, err - } - return SenderNonce(b), nil -} - -// use public key to create a deterministric transactionID -func newTransactionID(key crypto.PublicKey) (TransactionID, error) { - id, err := cryptoutil.GenerateSubjectKeyID(key) - if err != nil { - return "", err - } - - encHash := base64.StdEncoding.EncodeToString(id) - return TransactionID(encHash), nil -} diff --git a/scep/scep_test.go b/scep/scep_test.go deleted file mode 100644 index a9c6838..0000000 --- a/scep/scep_test.go +++ /dev/null @@ -1,351 +0,0 @@ -package scep_test - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "errors" - "io/ioutil" - "math/big" - "testing" - "time" - - "github.com/micromdm/scep/v2/cryptoutil" - "github.com/micromdm/scep/v2/depot" - "github.com/micromdm/scep/v2/scep" -) - -func testParsePKIMessage(t *testing.T, data []byte) *scep.PKIMessage { - msg, err := scep.ParsePKIMessage(data) - if err != nil { - t.Fatal(err) - } - validateParsedPKIMessage(t, msg) - return msg -} - -func validateParsedPKIMessage(t *testing.T, msg *scep.PKIMessage) { - if msg.TransactionID == "" { - t.Errorf("expected TransactionID attribute") - } - if msg.MessageType == "" { - t.Errorf("expected MessageType attribute") - } - switch msg.MessageType { - case scep.CertRep: - if len(msg.RecipientNonce) == 0 { - t.Errorf("expected RecipientNonce attribute") - } - case scep.PKCSReq, scep.UpdateReq, scep.RenewalReq: - if len(msg.SenderNonce) == 0 { - t.Errorf("expected SenderNonce attribute") - } - } -} - -// Tests the case when servers reply with PKCS #7 signed-data that contains no -// certificates assuming that the client can request CA certificates using -// GetCaCert request. -func TestParsePKIEnvelopeCert_MissingCertificatesForSigners(t *testing.T) { - certRepMissingCertificates := loadTestFile(t, "testdata/testca2/CertRep_NoCertificatesForSigners.der") - caPEM := loadTestFile(t, "testdata/testca2/ca2.pem") - - // Try to parse the PKIMessage without providing certificates for signers. - _, err := scep.ParsePKIMessage(certRepMissingCertificates) - if err == nil { - t.Fatal("parsed PKIMessage without providing signer certificates") - } - - signerCert := decodePEMCert(t, caPEM) - msg, err := scep.ParsePKIMessage(certRepMissingCertificates, scep.WithCACerts([]*x509.Certificate{signerCert})) - if err != nil { - t.Fatalf("failed to parse PKIMessage: %v", err) - } - validateParsedPKIMessage(t, msg) -} - -func TestDecryptPKIEnvelopeCSR(t *testing.T) { - pkcsReq := loadTestFile(t, "testdata/PKCSReq.der") - msg := testParsePKIMessage(t, pkcsReq) - cacert, cakey := loadCACredentials(t) - err := msg.DecryptPKIEnvelope(cacert, cakey) - if err != nil { - t.Fatal(err) - } - if msg.CSRReqMessage.CSR == nil { - t.Errorf("expected non-nil CSR field") - } -} - -func TestDecryptPKIEnvelopeCert(t *testing.T) { - certRep := loadTestFile(t, "testdata/CertRep.der") - testParsePKIMessage(t, certRep) - // clientcert, clientkey := loadClientCredentials(t) - // err = msg.DecryptPKIEnvelope(clientcert, clientkey) - // if err != nil { - // t.Fatal(err) - // } -} - -func TestSignCSR(t *testing.T) { - pkcsReq := loadTestFile(t, "testdata/PKCSReq.der") - msg := testParsePKIMessage(t, pkcsReq) - cacert, cakey := loadCACredentials(t) - err := msg.DecryptPKIEnvelope(cacert, cakey) - if err != nil { - t.Fatal(err) - } - csr := msg.CSRReqMessage.CSR - id, err := cryptoutil.GenerateSubjectKeyID(csr.PublicKey) - if err != nil { - t.Fatal(err) - } - tmpl := &x509.Certificate{ - SerialNumber: big.NewInt(4), - Subject: csr.Subject, - NotBefore: time.Now().Add(-600).UTC(), - NotAfter: time.Now().AddDate(1, 0, 0).UTC(), - SubjectKeyId: id, - ExtKeyUsage: []x509.ExtKeyUsage{ - x509.ExtKeyUsageAny, - x509.ExtKeyUsageClientAuth, - }, - } - // sign the CSR creating a DER encoded cert - crtBytes, err := x509.CreateCertificate(rand.Reader, tmpl, cacert, csr.PublicKey, cakey) - if err != nil { - t.Fatal(err) - } - crt, err := x509.ParseCertificate(crtBytes) - if err != nil { - t.Fatal(err) - } - certRep, err := msg.Success(cacert, cakey, crt) - if err != nil { - t.Fatal(err) - } - testParsePKIMessage(t, certRep.Raw) -} - -func TestNewCSRRequest(t *testing.T) { - for _, test := range []struct { - testName string - keyUsage x509.KeyUsage - certsSelectorFunc scep.CertsSelectorFunc - shouldCreateCSR bool - }{ - { - "KeyEncipherment not set with NOP certificates selector", - x509.KeyUsageCertSign, - scep.NopCertsSelector(), - true, - }, - { - "KeyEncipherment is set with NOP certificates selector", - x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment, - scep.NopCertsSelector(), - true, - }, - { - "KeyEncipherment not set with Encipherment certificates selector", - x509.KeyUsageCertSign, - scep.EnciphermentCertsSelector(), - false, - }, - { - "KeyEncipherment is set with Encipherment certificates selector", - x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment, - scep.EnciphermentCertsSelector(), - true, - }, - } { - test := test - t.Run(test.testName, func(t *testing.T) { - t.Parallel() - key, err := newRSAKey(2048) - if err != nil { - t.Fatal(err) - } - derBytes, err := newCSR(key, "john.doe@example.com", "US", "com.apple.scep.2379B935-294B-4AF1-A213-9BD44A2C6688") - if err != nil { - t.Fatal(err) - } - csr, err := x509.ParseCertificateRequest(derBytes) - if err != nil { - t.Fatal(err) - } - clientcert, clientkey := loadClientCredentials(t) - cacert, cakey := createCaCertWithKeyUsage(t, test.keyUsage) - tmpl := &scep.PKIMessage{ - MessageType: scep.PKCSReq, - Recipients: []*x509.Certificate{cacert}, - SignerCert: clientcert, - SignerKey: clientkey, - } - - pkcsreq, err := scep.NewCSRRequest(csr, tmpl, scep.WithCertsSelector(test.certsSelectorFunc)) - if test.shouldCreateCSR && err != nil { - t.Fatalf("keyUsage: %d, failed creating a CSR request: %v", test.keyUsage, err) - } - if !test.shouldCreateCSR && err == nil { - t.Fatalf("keyUsage: %d, shouldn't have created a CSR: %v", test.keyUsage, err) - } - if !test.shouldCreateCSR { - return - } - msg := testParsePKIMessage(t, pkcsreq.Raw) - err = msg.DecryptPKIEnvelope(cacert, cakey) - if err != nil { - t.Fatal(err) - } - }) - } -} - -// create a new RSA private key -func newRSAKey(bits int) (*rsa.PrivateKey, error) { - private, err := rsa.GenerateKey(rand.Reader, bits) - if err != nil { - return nil, err - } - return private, nil -} - -// create a CSR using the same parameters as Keychain Access would produce -func newCSR(priv *rsa.PrivateKey, email, country, cname string) ([]byte, error) { - subj := pkix.Name{ - Country: []string{country}, - CommonName: cname, - ExtraNames: []pkix.AttributeTypeAndValue{{ - Type: []int{1, 2, 840, 113549, 1, 9, 1}, - Value: email, - }}, - } - template := &x509.CertificateRequest{ - Subject: subj, - } - return x509.CreateCertificateRequest(rand.Reader, template, priv) -} - -func loadTestFile(t *testing.T, path string) []byte { - data, err := ioutil.ReadFile(path) - if err != nil { - t.Fatal(err) - } - return data -} - -// createCaCertWithKeyUsage generates a CA key and certificate with keyUsage. -func createCaCertWithKeyUsage(t *testing.T, keyUsage x509.KeyUsage) (*x509.Certificate, *rsa.PrivateKey) { - key, err := rsa.GenerateKey(rand.Reader, 2048) - if err != nil { - t.Fatal(err) - } - caCert := depot.NewCACert( - depot.WithCountry("US"), - depot.WithOrganization("MICROMDM"), - depot.WithCommonName("MICROMDM SCEP CA"), - depot.WithKeyUsage(keyUsage), - ) - crtBytes, err := caCert.SelfSign(rand.Reader, &key.PublicKey, key) - if err != nil { - t.Fatal(err) - } - cert, err := x509.ParseCertificate(crtBytes) - if err != nil { - t.Fatal(err) - } - return cert, key -} - -func loadCACredentials(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) { - cert, err := loadCertFromFile("testdata/testca/ca.crt") - if err != nil { - t.Fatal(err) - } - key, err := loadKeyFromFile("testdata/testca/ca.key") - if err != nil { - t.Fatal(err) - } - return cert, key -} - -func loadClientCredentials(t *testing.T) (*x509.Certificate, *rsa.PrivateKey) { - cert, err := loadCertFromFile("testdata/testclient/client.pem") - if err != nil { - t.Fatal(err) - } - key, err := loadKeyFromFile("testdata/testclient/client.key") - if err != nil { - t.Fatal(err) - } - return cert, key -} - -const ( - rsaPrivateKeyPEMBlockType = "RSA PRIVATE KEY" - certificatePEMBlockType = "CERTIFICATE" -) - -func loadCertFromFile(path string) (*x509.Certificate, error) { - data, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - pemBlock, _ := pem.Decode(data) - if pemBlock == nil { - return nil, errors.New("PEM decode failed") - } - if pemBlock.Type != certificatePEMBlockType { - return nil, errors.New("unmatched type or headers") - } - return x509.ParseCertificate(pemBlock.Bytes) -} - -// load an encrypted private key from disk -func loadKeyFromFile(path string) (*rsa.PrivateKey, error) { - data, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - pemBlock, _ := pem.Decode(data) - if pemBlock == nil { - return nil, errors.New("PEM decode failed") - } - if pemBlock.Type != rsaPrivateKeyPEMBlockType { - return nil, errors.New("unmatched type or headers") - } - - // testca key has a password - if len(pemBlock.Headers) > 0 { - password := []byte("") - b, err := x509.DecryptPEMBlock(pemBlock, password) - if err != nil { - return nil, err - } - return x509.ParsePKCS1PrivateKey(b) - } - - return x509.ParsePKCS1PrivateKey(pemBlock.Bytes) - -} - -func decodePEMCert(t *testing.T, data []byte) *x509.Certificate { - pemBlock, _ := pem.Decode(data) - if pemBlock == nil { - t.Fatal("PEM decode failed") - } - if pemBlock.Type != certificatePEMBlockType { - t.Fatal("unmatched type or headers") - } - - cert, err := x509.ParseCertificate(pemBlock.Bytes) - if err != nil { - t.Fatal(err) - } - return cert -} diff --git a/scep/testdata/CertRep.der b/scep/testdata/CertRep.der deleted file mode 100755 index 16ebc2b..0000000 Binary files a/scep/testdata/CertRep.der and /dev/null differ diff --git a/scep/testdata/testca2/CertRep_NoCertificatesForSigners.der b/scep/testdata/testca2/CertRep_NoCertificatesForSigners.der deleted file mode 100644 index 6ed5f52..0000000 Binary files a/scep/testdata/testca2/CertRep_NoCertificatesForSigners.der and /dev/null differ diff --git a/scep/testdata/testca2/ca2.pem b/scep/testdata/testca2/ca2.pem deleted file mode 100644 index b45d498..0000000 --- a/scep/testdata/testca2/ca2.pem +++ /dev/null @@ -1,101 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 47:00:00:00:02:f5:40:0d:75:85:dd:87:88:00:00:00:00:00:02 - Signature Algorithm: sha256WithRSAEncryption - Issuer: DC = org, DC = example, CN = example-CERT-PROV-CA - Validity - Not Before: Oct 30 19:07:21 2020 GMT - Not After : Oct 30 19:07:21 2022 GMT - Subject: C = US, CN = CERT-PROV-CA-MSCEP-RA - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (2048 bit) - Modulus: - 00:a1:0b:13:03:0a:fc:2f:ed:92:22:3f:a5:01:2d: - f9:46:f5:2c:fb:38:f9:0e:f1:b9:48:65:30:61:95: - 84:15:a2:15:68:16:61:5d:cb:d5:83:d4:69:c7:da: - 4a:79:a3:c4:a2:e7:5b:33:b1:bc:e0:a1:3e:4e:1b: - 96:be:ff:34:a1:a5:da:ca:cd:ee:99:5e:91:e3:dc: - 96:ba:92:0a:77:01:82:2c:cb:c9:b5:30:69:de:39: - d3:59:34:86:35:e4:ce:7f:ca:b5:7c:2a:58:14:21: - 2a:4f:d8:0d:c6:90:17:a3:29:2d:b2:1f:89:e9:53: - 10:5b:e3:36:01:af:6c:01:08:2c:e8:43:cc:89:3d: - 99:13:39:85:76:d8:18:3f:df:db:1a:4d:fd:fa:39: - fa:f6:7c:86:d9:70:1b:0f:3a:e8:6b:fa:3d:e5:e4: - 38:c1:3e:3c:d1:c5:c7:74:ca:77:74:a1:0c:f1:dd: - f4:28:9b:d9:99:7d:1e:e9:36:9f:6a:da:64:6e:90: - 59:58:d6:db:e8:e3:5c:08:41:30:bd:14:35:de:0c: - 4a:9a:9c:1c:1e:ce:86:7d:cc:be:47:37:f6:5c:c4: - 91:86:7e:9a:9f:9f:d0:de:49:e4:bd:71:b0:d1:33: - b1:1f:ca:43:fe:e7:b0:f1:48:cf:40:79:1a:2e:f8: - 30:d5 - Exponent: 65537 (0x10001) - X509v3 extensions: - 1.3.6.1.4.1.311.20.2: - .,.E.n.r.o.l.l.m.e.n.t.A.g.e.n.t.O.f.f.l.i.n.e - X509v3 Extended Key Usage: - 1.3.6.1.4.1.311.20.2.1 - X509v3 Key Usage: critical - Digital Signature - X509v3 Subject Key Identifier: - D2:DB:A3:DF:13:2B:EE:D5:88:A1:3E:8C:28:0E:2A:00:7B:C7:18:19 - X509v3 Authority Key Identifier: - keyid:4B:C5:63:29:BB:CF:68:AF:18:1E:C5:99:E8:DF:55:F7:23:9A:08:EB - - X509v3 CRL Distribution Points: - - Full Name: - URI:ldap:///CN=example-CERT-PROV-CA,CN=cert-prov-ca,CN=CDP,CN=Public%20Key%20Services,CN=Services,CN=Configuration,DC=example,DC=org?certificateRevocationList?base?objectClass=cRLDistributionPoint - - Authority Information Access: - CA Issuers - URI:ldap:///CN=example-CERT-PROV-CA,CN=AIA,CN=Public%20Key%20Services,CN=Services,CN=Configuration,DC=example,DC=org?cACertificate?base?objectClass=certificationAuthority - - Signature Algorithm: sha256WithRSAEncryption - 06:c8:d1:6f:ba:9b:48:84:a3:63:8e:4b:0d:73:85:91:7d:e4: - ce:50:9b:de:09:99:91:a3:1e:e6:ce:6f:ec:bf:2b:ce:bd:8d: - 0a:6c:0e:98:3f:b2:1f:cc:ab:53:62:2a:99:61:2d:76:9d:16: - 5d:27:f4:db:b6:9d:08:91:5b:cb:0c:18:09:b0:ab:38:e8:66: - ad:7b:45:53:81:11:16:aa:b2:5f:f6:ca:58:c0:fc:3c:98:04: - a6:0b:cd:28:28:8f:74:96:c4:57:7b:d1:a6:df:c8:ac:2f:cf: - 79:69:2e:ae:7c:e4:af:ad:ef:74:6f:c9:42:f7:03:3d:fe:48: - 25:05:d5:23:96:4a:4b:ed:a2:15:cf:b6:fe:06:d9:53:72:8e: - d2:14:3f:ab:83:db:22:e1:9b:16:51:f5:b6:ec:05:13:ad:2b: - fb:a4:1c:4c:97:17:29:5e:15:b9:f9:49:fb:33:7c:6d:b5:89: - ad:3d:50:64:9d:38:59:87:4d:9c:4f:39:44:48:34:96:77:f2: - 4b:1c:ad:84:94:e9:b7:9f:f7:1b:35:8a:c7:ab:18:14:59:d1: - f2:14:93:c3:a8:8f:6b:47:53:c9:9f:e2:f5:59:00:34:e6:23: - 2f:ce:5e:84:f9:81:ad:6b:cc:b3:ef:2c:04:5c:de:16:54:ba: - eb:38:f4:3b ------BEGIN CERTIFICATE----- -MIIFVDCCBDygAwIBAgITRwAAAAL1QA11hd2HiAAAAAAAAjANBgkqhkiG9w0BAQsF -ADBNMRMwEQYKCZImiZPyLGQBGRYDb3JnMRcwFQYKCZImiZPyLGQBGRYHZXhhbXBs -ZTEdMBsGA1UEAxMUZXhhbXBsZS1DRVJULVBST1YtQ0EwHhcNMjAxMDMwMTkwNzIx -WhcNMjIxMDMwMTkwNzIxWjAtMQswCQYDVQQGEwJVUzEeMBwGA1UEAxMVQ0VSVC1Q -Uk9WLUNBLU1TQ0VQLVJBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA -oQsTAwr8L+2SIj+lAS35RvUs+zj5DvG5SGUwYZWEFaIVaBZhXcvVg9Rpx9pKeaPE -oudbM7G84KE+ThuWvv80oaXays3umV6R49yWupIKdwGCLMvJtTBp3jnTWTSGNeTO -f8q1fCpYFCEqT9gNxpAXoyktsh+J6VMQW+M2Aa9sAQgs6EPMiT2ZEzmFdtgYP9/b -Gk39+jn69nyG2XAbDzroa/o95eQ4wT480cXHdMp3dKEM8d30KJvZmX0e6Tafatpk -bpBZWNbb6ONcCEEwvRQ13gxKmpwcHs6Gfcy+Rzf2XMSRhn6an5/Q3knkvXGw0TOx -H8pD/uew8UjPQHkaLvgw1QIDAQABo4ICSzCCAkcwOwYJKwYBBAGCNxQCBC4eLABF -AG4AcgBvAGwAbABtAGUAbgB0AEEAZwBlAG4AdABPAGYAZgBsAGkAbgBlMBUGA1Ud -JQQOMAwGCisGAQQBgjcUAgEwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBTS26Pf -Eyvu1YihPowoDioAe8cYGTAfBgNVHSMEGDAWgBRLxWMpu89orxgexZno31X3I5oI -6zCB1wYDVR0fBIHPMIHMMIHJoIHGoIHDhoHAbGRhcDovLy9DTj1leGFtcGxlLUNF -UlQtUFJPVi1DQSxDTj1jZXJ0LXByb3YtY2EsQ049Q0RQLENOPVB1YmxpYyUyMEtl -eSUyMFNlcnZpY2VzLENOPVNlcnZpY2VzLENOPUNvbmZpZ3VyYXRpb24sREM9ZXhh -bXBsZSxEQz1vcmc/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVj -dENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIHGBggrBgEFBQcBAQSBuTCBtjCB -swYIKwYBBQUHMAKGgaZsZGFwOi8vL0NOPWV4YW1wbGUtQ0VSVC1QUk9WLUNBLENO -PUFJQSxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1D -b25maWd1cmF0aW9uLERDPWV4YW1wbGUsREM9b3JnP2NBQ2VydGlmaWNhdGU/YmFz -ZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MA0GCSqGSIb3DQEB -CwUAA4IBAQAGyNFvuptIhKNjjksNc4WRfeTOUJveCZmRox7mzm/svyvOvY0KbA6Y -P7IfzKtTYiqZYS12nRZdJ/Tbtp0IkVvLDBgJsKs46Gate0VTgREWqrJf9spYwPw8 -mASmC80oKI90lsRXe9Gm38isL895aS6ufOSvre90b8lC9wM9/kglBdUjlkpL7aIV -z7b+BtlTco7SFD+rg9si4ZsWUfW27AUTrSv7pBxMlxcpXhW5+Un7M3xttYmtPVBk -nThZh02cTzlESDSWd/JLHK2ElOm3n/cbNYrHqxgUWdHyFJPDqI9rR1PJn+L1WQA0 -5iMvzl6E+YGta8yz7ywEXN4WVLrrOPQ7 ------END CERTIFICATE----- diff --git a/scep/testdata/testclient/client.key b/scep/testdata/testclient/client.key deleted file mode 100644 index be2febb..0000000 --- a/scep/testdata/testclient/client.key +++ /dev/null @@ -1,19 +0,0 @@ -Bag Attributes - friendlyName: com.apple.security.scep.063D7953-1338-4BF0-8F99-913382996224 - localKeyID: A1 30 90 76 1A 30 F6 66 64 F8 5D 37 43 3D 20 65 E1 11 2B A1 -Key Attributes: ------BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQDT9YGr0H8dpozAEi5l2XkWyKy2JD3yEybI9A1ZDXcK/78UPQ+C -4tBb6BTRJWDWoZFlFcHUGbZWXbySPw6ggBsLl4feF1A+hjtCjlZsRF4mnfctixkr -dP+UGl37UunsW63mn8uM6oM+7elhB2zRscZrZPBDKZx1V+Et+BFrX49xNwIDAQAB -AoGAP9bzDmfG0YxnWjZfqSd+NCGO+3EhAzdHeEEhgA/xKevrhlH5yQc9kGDvXCrw -5tRU8WhDL/nqlEq5UCcT5b2P5zp1L0PY+X6gD5C7KGEIio5SvimAnQMh2HCKftDc -KX9NA9EJLq9BUsqK9HjXdsfIGzyoqhZQpDGTrgyVlfm/zwkCQQDyuKJvxm/6tWry -GBN0eBLyA4F738MFP/3kb87zUsGTD8dh92vwjMhGv1woKp09POs2s2MnADw2wOEa -hh+v6R5zAkEA344KSwaKZZSf7E5qFayg3qG9M55uhbus9CazoAWiceYMR6ImIevA -EtnhwQczIRGI8Bp4jgUtO9gu4IgjCUHNLQJBAIJkS+cuPGP75+sMog70noDi/0GT -0MnWOcfphMzUzWb6mAr6B0Of7cuL668sTXJjcpzdO8vs5WworAU6vnUbEB8CQQCB -+Hy3fcf8otoPcs9uZnzosrPjTNsI2UIGeHG6OUxmV88P3o+47O0wiIgdx2fMc/tf -TKSGPTA9OMSYOc3U1fLJAkEArLyCHxxDzcEuhyHnmoct/dTUg5Q8CYKIQfo5oVKZ -jvtL/r0udFpxLUDxZ7590I32cTSrtfgNBJegHr54YKN9KA== ------END RSA PRIVATE KEY----- diff --git a/scep/testdata/testclient/client.pem b/scep/testdata/testclient/client.pem deleted file mode 100644 index 3de2027..0000000 --- a/scep/testdata/testclient/client.pem +++ /dev/null @@ -1,58 +0,0 @@ -Certificate: - Data: - Version: 3 (0x2) - Serial Number: - 6f:4f:31:6a:b2:da:d4:ce:d0:fc:09:fb:b9:26:90:03:d6:09:a4:8c - Signature Algorithm: sha256WithRSAEncryption - Issuer: C = US, ST = USA, O = etcd-ca, OU = CA, CN = etcd-ca - Validity - Not Before: Feb 16 12:11:45 2021 GMT - Not After : Dec 26 12:11:45 2030 GMT - Subject: C = US, ST = USA, O = etcd-ca, OU = CA, CN = etcd-ca - Subject Public Key Info: - Public Key Algorithm: rsaEncryption - RSA Public-Key: (1024 bit) - Modulus: - 00:d3:f5:81:ab:d0:7f:1d:a6:8c:c0:12:2e:65:d9: - 79:16:c8:ac:b6:24:3d:f2:13:26:c8:f4:0d:59:0d: - 77:0a:ff:bf:14:3d:0f:82:e2:d0:5b:e8:14:d1:25: - 60:d6:a1:91:65:15:c1:d4:19:b6:56:5d:bc:92:3f: - 0e:a0:80:1b:0b:97:87:de:17:50:3e:86:3b:42:8e: - 56:6c:44:5e:26:9d:f7:2d:8b:19:2b:74:ff:94:1a: - 5d:fb:52:e9:ec:5b:ad:e6:9f:cb:8c:ea:83:3e:ed: - e9:61:07:6c:d1:b1:c6:6b:64:f0:43:29:9c:75:57: - e1:2d:f8:11:6b:5f:8f:71:37 - Exponent: 65537 (0x10001) - X509v3 extensions: - X509v3 Subject Key Identifier: - A1:30:90:76:1A:30:F6:66:64:F8:5D:37:43:3D:20:65:E1:11:2B:A1 - X509v3 Authority Key Identifier: - keyid:A1:30:90:76:1A:30:F6:66:64:F8:5D:37:43:3D:20:65:E1:11:2B:A1 - - X509v3 Basic Constraints: critical - CA:TRUE - Signature Algorithm: sha256WithRSAEncryption - 96:f0:7b:28:3b:7a:06:2e:cd:37:23:19:f3:98:0c:a2:d3:16: - 9e:5a:b7:56:ca:9d:9d:ca:a4:59:78:b3:29:b1:3c:18:e8:dc: - 4c:f6:64:62:84:a3:19:ca:ca:b0:34:ed:d2:6f:9b:a6:38:20: - 98:64:db:c5:cb:a4:ce:b2:9c:62:a2:0e:e2:76:cb:f4:a1:c5: - 40:ee:c5:b4:18:9d:9e:5a:bf:bd:72:29:96:f8:82:05:87:d3: - fb:84:12:91:ea:e0:86:02:b1:63:c2:59:6a:10:9a:b7:7d:e2: - be:f3:19:31:31:3e:bb:21:4d:a0:16:f9:c0:94:ba:0f:e6:3d: - 37:26 ------BEGIN CERTIFICATE----- -MIICdDCCAd2gAwIBAgIUb08xarLa1M7Q/An7uSaQA9YJpIwwDQYJKoZIhvcNAQEL -BQAwTDELMAkGA1UEBhMCVVMxDDAKBgNVBAgMA1VTQTEQMA4GA1UECgwHZXRjZC1j -YTELMAkGA1UECwwCQ0ExEDAOBgNVBAMMB2V0Y2QtY2EwHhcNMjEwMjE2MTIxMTQ1 -WhcNMzAxMjI2MTIxMTQ1WjBMMQswCQYDVQQGEwJVUzEMMAoGA1UECAwDVVNBMRAw -DgYDVQQKDAdldGNkLWNhMQswCQYDVQQLDAJDQTEQMA4GA1UEAwwHZXRjZC1jYTCB -nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0/WBq9B/HaaMwBIuZdl5FsistiQ9 -8hMmyPQNWQ13Cv+/FD0PguLQW+gU0SVg1qGRZRXB1Bm2Vl28kj8OoIAbC5eH3hdQ -PoY7Qo5WbEReJp33LYsZK3T/lBpd+1Lp7Fut5p/LjOqDPu3pYQds0bHGa2TwQymc -dVfhLfgRa1+PcTcCAwEAAaNTMFEwHQYDVR0OBBYEFKEwkHYaMPZmZPhdN0M9IGXh -ESuhMB8GA1UdIwQYMBaAFKEwkHYaMPZmZPhdN0M9IGXhESuhMA8GA1UdEwEB/wQF -MAMBAf8wDQYJKoZIhvcNAQELBQADgYEAlvB7KDt6Bi7NNyMZ85gMotMWnlq3Vsqd -ncqkWXizKbE8GOjcTPZkYoSjGcrKsDTt0m+bpjggmGTbxcukzrKcYqIO4nbL9KHF -QO7FtBidnlq/vXIplviCBYfT+4QSkerghgKxY8JZahCat33ivvMZMTE+uyFNoBb5 -wJS6D+Y9NyY= ------END CERTIFICATE----- diff --git a/server/csrsigner.go b/server/csrsigner.go index 1ddfad0..bfae310 100644 --- a/server/csrsigner.go +++ b/server/csrsigner.go @@ -6,7 +6,7 @@ import ( "crypto/x509" "errors" - "github.com/micromdm/scep/v2/scep" + "github.com/smallstep/scep" ) // CSRSignerContext is a handler for signing CSRs by a CA/RA. diff --git a/server/csrsigner_test.go b/server/csrsigner_test.go index 62696de..5e24b8c 100644 --- a/server/csrsigner_test.go +++ b/server/csrsigner_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/micromdm/scep/v2/scep" + "github.com/smallstep/scep" ) func TestChallengeMiddleware(t *testing.T) { diff --git a/server/service.go b/server/service.go index b20eb47..e0bfcef 100644 --- a/server/service.go +++ b/server/service.go @@ -6,9 +6,8 @@ import ( "crypto/x509" "errors" - "github.com/micromdm/scep/v2/scep" - "github.com/go-kit/kit/log" + "github.com/smallstep/scep" ) // Service is the interface for all supported SCEP server operations. diff --git a/server/service_bolt_test.go b/server/service_bolt_test.go index 74df9f0..66ae329 100644 --- a/server/service_bolt_test.go +++ b/server/service_bolt_test.go @@ -17,10 +17,10 @@ import ( challengestore "github.com/micromdm/scep/v2/challenge/bolt" scepdepot "github.com/micromdm/scep/v2/depot" boltdepot "github.com/micromdm/scep/v2/depot/bolt" - "github.com/micromdm/scep/v2/scep" scepserver "github.com/micromdm/scep/v2/server" "github.com/boltdb/bolt" + "github.com/smallstep/scep" ) func TestCaCert(t *testing.T) { diff --git a/server/transport_test.go b/server/transport_test.go index ccaaadf..9c7921e 100644 --- a/server/transport_test.go +++ b/server/transport_test.go @@ -33,7 +33,7 @@ func TestCACaps(t *testing.T) { } func TestEncodePKCSReq_Request(t *testing.T) { - pkcsreq := loadTestFile(t, "../scep/testdata/PKCSReq.der") + pkcsreq := loadTestFile(t, "../testdata/PKCSReq.der") msg := scepserver.SCEPRequest{ Operation: "PKIOperation", Message: pkcsreq, @@ -88,7 +88,7 @@ func TestGetCACertMessage(t *testing.T) { func TestPKIOperation(t *testing.T) { server, _, teardown := newServer(t) defer teardown() - pkcsreq := loadTestFile(t, "../scep/testdata/PKCSReq.der") + pkcsreq := loadTestFile(t, "../testdata/PKCSReq.der") body := bytes.NewReader(pkcsreq) url := server.URL + "/scep?operation=PKIOperation" resp, err := http.Post(url, "", body) @@ -103,7 +103,7 @@ func TestPKIOperation(t *testing.T) { func TestPKIOperationGET(t *testing.T) { server, _, teardown := newServer(t) defer teardown() - pkcsreq := loadTestFile(t, "../scep/testdata/PKCSReq.der") + pkcsreq := loadTestFile(t, "../testdata/PKCSReq.der") message := base64.StdEncoding.EncodeToString(pkcsreq) req, err := http.NewRequest("GET", server.URL+"/scep", nil) if err != nil { @@ -126,7 +126,7 @@ func newServer(t *testing.T, opts ...scepserver.ServiceOption) (*httptest.Server var err error var depot depot.Depot // cert storage { - depot, err = filedepot.NewFileDepot("../scep/testdata/testca") + depot, err = filedepot.NewFileDepot("../testdata/testca") if err != nil { t.Fatal(err) } diff --git a/scep/testdata/PKCSReq.der b/testdata/PKCSReq.der similarity index 100% rename from scep/testdata/PKCSReq.der rename to testdata/PKCSReq.der diff --git a/scep/testdata/testca/ca.crt b/testdata/testca/ca.crt similarity index 100% rename from scep/testdata/testca/ca.crt rename to testdata/testca/ca.crt diff --git a/scep/testdata/testca/ca.crt.info b/testdata/testca/ca.crt.info similarity index 100% rename from scep/testdata/testca/ca.crt.info rename to testdata/testca/ca.crt.info diff --git a/scep/testdata/testca/ca.key b/testdata/testca/ca.key similarity index 100% rename from scep/testdata/testca/ca.key rename to testdata/testca/ca.key diff --git a/scep/testdata/testca/ca.pem b/testdata/testca/ca.pem similarity index 100% rename from scep/testdata/testca/ca.pem rename to testdata/testca/ca.pem diff --git a/scep/testdata/testca/sceptest.mobileconfig b/testdata/testca/sceptest.mobileconfig similarity index 100% rename from scep/testdata/testca/sceptest.mobileconfig rename to testdata/testca/sceptest.mobileconfig