scep

package module
v3.0.0-...-6f10280 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2023 License: MIT Imports: 13 Imported by: 0

README

scep

CI Go Reference

scep is a Simple Certificate Enrollment Protocol server and client

Installation

Binary releases are available on the releases page.

Compiling from source

To compile the SCEP client and server you will need a Go compiler as well as standard tools like git, make, etc.

  1. Clone the repository and get into the source directory: git clone https://github.com/micromdm/scep.git && cd scep
  2. Compile the client and server binaries: make

The binaries will be compiled in the current directory and named after the architecture. I.e. scepclient-linux-amd64 and scepserver-linux-amd64.

Docker

See Docker documentation below.

Example setup

Minimal example for both server and client.

# SERVER:
# create a new CA
./scepserver-linux-amd64 ca -init
# start server
./scepserver-linux-amd64 -depot depot -port 2016 -challenge=secret

# SCEP request:
# in a separate terminal window, run a client
# note, if the client.key doesn't exist, the client will create a new rsa private key. Must be in PEM format.
./scepclient-linux-amd64 -private-key client.key -server-url=http://127.0.0.1:2016/scep -challenge=secret

# NDES request:
# note, this should point to an NDES server, scepserver does not provide NDES.
./scepclient-linux-amd64 -private-key client.key -server-url=https://scep.example.com:4321/certsrv/mscep/ -ca-fingerprint="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

Server Usage

The default flags configure and run the scep server.

-depot must be the path to a folder with ca.pem and ca.key files. If you don't already have a CA to use, you can create one using the ca subcommand.

The scepserver provides one HTTP endpoint, /scep, that facilitates the normal PKIOperation/Message parameters.

Server usage:

$ ./scepserver-linux-amd64 -help
  -allowrenew string
    	do not allow renewal until n days before expiry, set to 0 to always allow (default "14")
  -capass string
    	passwd for the ca.key
  -challenge string
    	enforce a challenge password
  -crtvalid string
    	validity for new client certificates in days (default "365")
  -csrverifierexec string
    	will be passed the CSRs for verification
  -debug
    	enable debug logging
  -depot string
    	path to ca folder (default "depot")
  -log-json
    	output JSON logs
  -port string
    	port to listen on (default "8080")
  -version
    	prints version information
usage: scep [<command>] [<args>]
 ca <args> create/manage a CA
type <command> --help to see usage for each subcommand

Use the ca -init subcommand to create a new CA and private key.

CA sub-command usage:

$ ./scepserver-linux-amd64 ca -help
Usage of ca:
  -country string
    	country for CA cert (default "US")
  -depot string
    	path to ca folder (default "depot")
  -init
    	create a new CA
  -key-password string
    	password to store rsa key
  -keySize int
    	rsa key size (default 4096)
  -common_name string
        common name (CN) for CA cert (default "MICROMDM SCEP CA")
  -organization string
    	organization for CA cert (default "scep-ca")
  -organizational_unit string
    	organizational unit (OU) for CA cert (default "SCEP CA")
  -years int
    	default CA years (default 10)
CSR verifier

The -csrverifierexec switch to the SCEP server allows for executing a command before a certificate is issued to verify the submitted CSR. Scripts exiting without errors (zero exit status) will proceed to certificate issuance, otherwise a SCEP error is generated to the client. For example if you wanted to just save the CSR this is a valid CSR verifier shell script:

#!/bin/sh

cat - > /tmp/scep.csr

Client Usage

$ ./scepclient-linux-amd64 -help
Usage of ./scepclient-linux-amd64:
  -ca-fingerprint string
    	SHA-256 digest of CA certificate for NDES server. Note: Changed from MD5.
  -certificate string
    	certificate path, if there is no key, scepclient will create one
  -challenge string
    	enforce a challenge password
  -cn string
    	common name for certificate (default "scepclient")
  -country string
    	country code in certificate (default "US")
  -debug
    	enable debug logging
  -keySize int
    	rsa key size (default 2048)
  -locality string
    	locality for certificate
  -log-json
    	use JSON for log output
  -organization string
    	organization for cert (default "scep-client")
  -ou string
    	organizational unit for certificate (default "MDM")
  -private-key string
    	private key path, if there is no key, scepclient will create one
  -province string
    	province for certificate
  -server-url string
    	SCEP server url
  -version
    	prints version information

Note: Make sure to specify the desired endpoint in your -server-url value (e.g. 'http://scep.groob.io:2016/scep')

To obtain a certificate through Network Device Enrollment Service (NDES), set -server-url to a server that provides NDES. This most likely uses the /certsrv/mscep path. You will need to add the -ca-fingerprint client argument during this request to specify which CA to use.

If you're not sure which SHA-256 hash (for a specific CA) to use, you can use the -debug flag to print them out for the CAs returned from the SCEP server.

Docker

# first compile the Docker binaries
make docker

# build the image
docker build -t micromdm/scep:latest .

# create CA
docker run -it --rm -v /path/to/ca/folder:/depot micromdm/scep:latest ca -init

# run
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.

Example (server):

// 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.

The SCEP server includes a built-in CA/certificate store. This is facilitated by the Depot and CSRSigner Go interfaces. This certificate storage to happen however you want. It also allows for swapping out the entire CA signer altogether or even using SCEP as a proxy for certificates.

Documentation

Overview

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

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CACerts

func CACerts(data []byte) ([]*x509.Certificate, error)

CACerts extract CA Certificate or chain from pkcs7 degenerate signed data

func DegenerateCertificates

func DegenerateCertificates(certs []*x509.Certificate) ([]byte, error)

DegenerateCertificates creates degenerate certificates pkcs#7 type

Types

type CSRReqMessage

type CSRReqMessage struct {
	RawDecrypted []byte

	// PKCS#10 Certificate request inside the envelope
	CSR *x509.CertificateRequest

	ChallengePassword string
}

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 CertRepMessage

type CertRepMessage struct {
	PKIStatus
	RecipientNonce
	FailInfo

	Certificate *x509.Certificate
	// contains filtered or unexported fields
}

CertRepMessage is a type of PKIMessage

type CertsSelector

type CertsSelector interface {
	SelectCerts([]*x509.Certificate) []*x509.Certificate
}

A CertsSelector filters certificates.

type CertsSelectorFunc

type CertsSelectorFunc func([]*x509.Certificate) []*x509.Certificate

CertsSelectorFunc is a type of function that filters certificates.

func EnciphermentCertsSelector

func EnciphermentCertsSelector() CertsSelectorFunc

A EnciphermentCertsSelector returns a CertsSelectorFunc that selects certificates eligible for key encipherment. This certsSelector can be used to filter PKCSReq recipients.

func FingerprintCertsSelector

func FingerprintCertsSelector(hashType crypto.Hash, hash []byte) CertsSelectorFunc

FingerprintCertsSelector selects a certificate that matches hash using hashType against the digest of the raw certificate DER bytes

func NopCertsSelector

func NopCertsSelector() CertsSelectorFunc

NopCertsSelector returns a CertsSelectorFunc that does not do anything.

func (CertsSelectorFunc) SelectCerts

func (f CertsSelectorFunc) SelectCerts(certs []*x509.Certificate) []*x509.Certificate

type FailInfo

type FailInfo string

FailInfo is a SCEP failInfo attribute

The FailInfo attribute MUST contain one of the following failure reasons:

const (
	BadAlg          FailInfo = "0"
	BadMessageCheck FailInfo = "1"
	BadRequest      FailInfo = "2"
	BadTime         FailInfo = "3"
	BadCertID       FailInfo = "4"
)

func (FailInfo) String

func (info FailInfo) String() string

type Logger

type Logger interface {
	Log(keyvals ...interface{}) error
}

Logger is the fundamental interface for all SCEP logging operations. It has the same signature as the `github.com/go-kit/kit/log` interface, to allow for interop between the two. Log creates a log event from keyvals, a variadic sequence of alternating keys and values. Implementations must be safe for concurrent use by multiple goroutines. In particular, any implementation of Logger that appends to keyvals or modifies or retains any of its elements must make a copy first.

type MessageType

type MessageType string

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:

const (
	CertRep    MessageType = "3"
	RenewalReq MessageType = "17"
	UpdateReq  MessageType = "18"
	PKCSReq    MessageType = "19"
	CertPoll   MessageType = "20"
	GetCert    MessageType = "21"
	GetCRL     MessageType = "22"
)

Undefined message types are treated as an error.

func (MessageType) String

func (msg MessageType) String() string

type Option

type Option func(*config)

Option specifies custom configuration for SCEP.

func WithCACerts

func WithCACerts(caCerts []*x509.Certificate) Option

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 WithCertsSelector

func WithCertsSelector(selector CertsSelector) Option

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 WithLogger

func WithLogger(logger Logger) Option

WithLogger adds option logging to the SCEP operations.

type PKIMessage

type PKIMessage struct {
	TransactionID
	MessageType
	SenderNonce
	*CertRepMessage
	*CSRReqMessage

	// DER Encoded PKIMessage
	Raw []byte

	// Used to encrypt message
	Recipients []*x509.Certificate

	// Signer info
	SignerKey  *rsa.PrivateKey
	SignerCert *x509.Certificate
	// contains filtered or unexported fields
}

PKIMessage defines the possible SCEP message types

func NewCSRRequest

func NewCSRRequest(csr *x509.CertificateRequest, tmpl *PKIMessage, opts ...Option) (*PKIMessage, error)

NewCSRRequest creates a scep PKI PKCSReq/UpdateReq message

func ParsePKIMessage

func ParsePKIMessage(data []byte, opts ...Option) (*PKIMessage, error)

ParsePKIMessage unmarshals a PKCS#7 signed data into a PKI message struct

func (*PKIMessage) DecryptPKIEnvelope

func (msg *PKIMessage) DecryptPKIEnvelope(cert *x509.Certificate, key *rsa.PrivateKey) error

DecryptPKIEnvelope decrypts the pkcs envelopedData inside the SCEP PKIMessage

func (*PKIMessage) Fail

func (msg *PKIMessage) Fail(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, info FailInfo) (*PKIMessage, error)

func (*PKIMessage) Success

func (msg *PKIMessage) Success(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, crt *x509.Certificate) (*PKIMessage, error)

Success returns a new PKIMessage with CertRep data using an already-issued certificate

type PKIStatus

type PKIStatus string

PKIStatus is a SCEP pkiStatus attribute which holds transaction status information. All SCEP responses MUST include a pkiStatus.

The following pkiStatuses are defined:

const (
	SUCCESS PKIStatus = "0"
	FAILURE PKIStatus = "2"
	PENDING PKIStatus = "3"
)

Undefined pkiStatus attributes are treated as an error

type RecipientNonce

type RecipientNonce []byte

The RecipientNonce MUST be copied from the SenderNonce and included in the reply.

type SenderNonce

type SenderNonce []byte

SenderNonce is a random 16 byte number. A sender must include the senderNonce in each transaction to a recipient.

type TransactionID

type TransactionID string

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.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL