diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..bb53d48 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,56 @@ +name: Bug Report +description: File a bug report +title: "[Bug]: " +labels: ["bug", "needs triage"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: textarea + id: steps + attributes: + label: Steps to Reproduce + description: Tell us how to reproduce this issue. + placeholder: These are the steps! + validations: + required: true + - type: textarea + id: your-env + attributes: + label: Your Environment + value: |- + * OS - + * Version - + validations: + required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected Behavior + description: What did you expect to happen? + validations: + required: true + - type: textarea + id: actual-behavior + attributes: + label: Actual Behavior + description: What happens instead? + validations: + required: true + - type: textarea + id: context + attributes: + label: Additional Context + description: Add any other context about the problem here. + validations: + required: false + - type: textarea + id: contributing + attributes: + label: Contributing + value: | + Vote on this issue by adding a ๐Ÿ‘ reaction. + To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already). + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..4ddc03c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Ask on Discord + url: https://discord.gg/7xgjhVAg6g + about: You can ask for help here! + - name: Want to contribute to scep? + url: https://github.com/smallstep/cli/blob/master/docs/CONTRIBUTING.md + about: Be sure to read contributing guidelines! diff --git a/.github/ISSUE_TEMPLATE/documentation-request.md b/.github/ISSUE_TEMPLATE/documentation-request.md new file mode 100644 index 0000000..a8e0a9e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation-request.md @@ -0,0 +1,14 @@ +--- +name: Documentation Request +about: Request documentation for a feature +title: '' +labels: docs, needs triage +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md new file mode 100644 index 0000000..eb529e5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -0,0 +1,13 @@ +--- +name: Enhancement +about: Suggest an enhancement to scep +title: '' +labels: enhancement, needs triage +assignees: '' + +--- + +### What would you like to be added + + +### Why this is needed diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE new file mode 100644 index 0000000..5d38f10 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE @@ -0,0 +1,20 @@ + +#### Name of feature: + +#### Pain or issue this feature alleviates: + +#### Why is this important to the project (if not answered above): + +#### Is there documentation on how to use this feature? If so, where? + +#### In what environments or workflows is this feature supported? + +#### In what environments or workflows is this feature explicitly NOT supported (if any)? + +#### Supporting links/other PRs/issues: + +๐Ÿ’”Thank you! diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 362f1cf..acf3722 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -2,32 +2,21 @@ name: CI on: push: - branches: [ main ] + tags-ignore: + - 'v*' + branches: + - "main" pull_request: - types: [opened, reopened, synchronize] + workflow_call: -jobs: - build-test: - name: Build, test & format - strategy: - matrix: - go-version: [1.15.x, 1.16.x] - platform: [ubuntu-latest, macos-latest, windows-latest] - runs-on: ${{ matrix.platform }} - steps: - - uses: actions/checkout@v2 - - - name: setup go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - - - name: Build - run: go build -v ./... +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true - - name: Test - run: go test -v ./... - - - name: Format - if: matrix.platform == 'ubuntu-latest' - run: if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then exit 1; fi +jobs: + ci: + uses: smallstep/workflows/.github/workflows/goCI.yml@main + with: + run-build: false + run-codeql: true + secrets: inherit diff --git a/.github/workflows/ci-legacy.yml b/.github/workflows/ci-legacy.yml new file mode 100644 index 0000000..02b077c --- /dev/null +++ b/.github/workflows/ci-legacy.yml @@ -0,0 +1,38 @@ +# keeping the legacy CI around for backwards compatibility checks on v1 +name: CI (Legacy) + +on: + push: + branches: [ main ] + pull_request: + types: [opened, reopened, synchronize] + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + build-test: + name: Build, test & format + strategy: + matrix: + go-version: [1.16.x, 1.17.x, 1.18.x] + platform: [ubuntu-latest] + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v3 + + - name: setup go + uses: actions/setup-go@v3 + with: + go-version: ${{ matrix.go-version }} + + - name: Build + run: go build -v ./... + + - name: Test + run: go test -v ./... + + - name: Format + if: matrix.platform == 'ubuntu-latest' + run: if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then exit 1; fi \ No newline at end of file diff --git a/.github/workflows/code-scan-cron.yml b/.github/workflows/code-scan-cron.yml new file mode 100644 index 0000000..e235db3 --- /dev/null +++ b/.github/workflows/code-scan-cron.yml @@ -0,0 +1,7 @@ +on: + schedule: + - cron: '0 0 * * SUN' + +jobs: + code-scan: + uses: smallstep/workflows/.github/workflows/code-scan.yml@main diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..1d25991 --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,22 @@ +name: Dependabot auto-merge +on: pull_request + +permissions: + contents: write + pull-requests: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v1.1.1 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + - name: Enable auto-merge for Dependabot PRs + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..d4cc344 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,36 @@ +name: Create Release + +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +jobs: + ci: + uses: smallstep/crypto/.github/workflows/ci.yml@master + secrets: inherit + + create_release: + name: Create Release + needs: ci + runs-on: ubuntu-latest + steps: + - name: Is Pre-release + id: is_prerelease + run: | + set +e + echo ${{ github.ref }} | grep "\-rc.*" + OUT=$? + if [ $OUT -eq 0 ]; then IS_PRERELEASE=true; else IS_PRERELEASE=false; fi + echo "IS_PRERELEASE=${IS_PRERELEASE}" >> ${GITHUB_OUTPUT} + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: ${{ steps.is_prerelease.outputs.IS_PRERELEASE }} diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml new file mode 100644 index 0000000..8e87963 --- /dev/null +++ b/.github/workflows/triage.yml @@ -0,0 +1,16 @@ +name: Add Issues and PRs to Triage + +on: + issues: + types: + - opened + - reopened + pull_request_target: + types: + - opened + - reopened + +jobs: + triage: + uses: smallstep/workflows/.github/workflows/triage.yml@main + secrets: inherit \ No newline at end of file diff --git a/.gitignore b/.gitignore index b0bbd25..10be5d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,23 @@ -scepserver-* -scepclient-* +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Go Workspaces +go.work +go.work.sum + +# Development +.vscode/ +coverage.cov + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +/vendor \ No newline at end of file diff --git a/Makefile b/Makefile index e13e4ea..bb5e266 100644 --- a/Makefile +++ b/Makefile @@ -1,46 +1,3 @@ -VERSION=$(shell git describe --tags --always --dirty) -LDFLAGS=-ldflags "-X main.version=$(VERSION)" -OSARCH=$(shell go env GOHOSTOS)-$(shell go env GOHOSTARCH) - -SCEPCLIENT=\ - scepclient-linux-amd64 \ - scepclient-linux-arm \ - scepclient-darwin-amd64 \ - scepclient-darwin-arm64 \ - scepclient-freebsd-amd64 \ - scepclient-windows-amd64.exe - -SCEPSERVER=\ - scepserver-linux-amd64 \ - scepserver-linux-arm \ - scepserver-darwin-amd64 \ - scepserver-darwin-arm64 \ - scepserver-freebsd-amd64 \ - scepserver-windows-amd64.exe - -my: scepclient-$(OSARCH) scepserver-$(OSARCH) - -docker: scepclient-linux-amd64 scepserver-linux-amd64 - -$(SCEPCLIENT): - GOOS=$(word 2,$(subst -, ,$@)) GOARCH=$(word 3,$(subst -, ,$(subst .exe,,$@))) go build $(LDFLAGS) -o $@ ./cmd/scepclient - -$(SCEPSERVER): - GOOS=$(word 2,$(subst -, ,$@)) GOARCH=$(word 3,$(subst -, ,$(subst .exe,,$@))) go build $(LDFLAGS) -o $@ ./cmd/scepserver - -%-$(VERSION).zip: %.exe - rm -f $@ - zip $@ $< - -%-$(VERSION).zip: % - rm -f $@ - zip $@ $< - -release: $(foreach bin,$(SCEPCLIENT) $(SCEPSERVER),$(subst .exe,,$(bin))-$(VERSION).zip) - -clean: - rm -f scepclient-* scepserver-* - test: go test -cover ./... @@ -48,4 +5,4 @@ test: test-race: go test -cover -race ./... -.PHONY: my docker $(SCEPCLIENT) $(SCEPSERVER) release clean test test-race +.PHONY: test test-race diff --git a/README.md b/README.md index 7875522..90bddc1 100644 --- a/README.md +++ b/README.md @@ -1,191 +1,21 @@ # scep -[![CI](https://github.com/micromdm/scep/workflows/CI/badge.svg)](https://github.com/micromdm/scep/actions) -[![Go Reference](https://pkg.go.dev/badge/github.com/micromdm/scep/v2.svg)](https://pkg.go.dev/github.com/micromdm/scep/v2) +`scep` is a Golang implementation of the Simple Certificate Enrollment Protocol (SCEP). -`scep` is a Simple Certificate Enrollment Protocol server and client +This package started its life as part of [micromdm/scep](https://github.com/micromdm/scep). +The core SCEP protocol was extracted from it and is now being maintained by [smallstep](https://smallstep.com). -## Installation +## Usage -Binary releases are available on the [releases page](https://github.com/micromdm/scep/releases). - -### Compiling from source - -To compile the SCEP client and server you will need [a Go compiler](https://golang.org/dl/) 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: -```sh -$ ./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 [] [] - ca create/manage a CA -type --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: - -```sh -#!/bin/sh - -cat - > /tmp/scep.csr -``` - -## Client Usage - -```sh -$ ./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 +```console +go get github.com/smallstep/scep ``` -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. +The package can be used for both client and server operations. -## Docker +For detailed usage, see the [Go Reference](https://pkg.go.dev/github.com/smallstep/scep). -```sh -# 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](https://pkg.go.dev/github.com/micromdm/scep/v2/scep). - -Example (server): +Example server: ```go // read a request body containing SCEP message @@ -226,9 +56,3 @@ if err != nil { // 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). - -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.