Skip to content

Commit a7538c5

Browse files
authored
Allow setting CN and validity days on certificate generation (#6)
1 parent 077b73d commit a7538c5

File tree

6 files changed

+66
-18
lines changed

6 files changed

+66
-18
lines changed

cmd/deptokens/main.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,15 @@ import (
1313
"github.com/micromdm/nanodep/tokenpki"
1414
)
1515

16-
const (
17-
defaultCN = "deptokens"
18-
defaultDays = 1
19-
)
20-
2116
// overridden by -ldflags -X
2217
var version = "unknown"
2318

2419
func main() {
2520
var (
2621
flCert = flag.String("cert", "cert.pem", "path to certificate")
2722
flKey = flag.String("key", "cert.key", "path to key")
23+
flCN = flag.String("cn", "deptokens", "common name to use when creating the certificate")
24+
flDays = flag.Int64("days", 1, "validity of the certificate in days")
2825
flPassword = flag.String("password", "", "password to encrypt/decrypt private key with")
2926
flTokens = flag.String("token", "", "path to tokens")
3027
flForce = flag.Bool("f", false, "force overwriting the keypair")
@@ -39,10 +36,14 @@ func main() {
3936

4037
var err error
4138
if *flTokens == "" {
39+
if *flDays <= 0 {
40+
fmt.Println("ERROR: invalid -days flag")
41+
os.Exit(1)
42+
}
4243
if *flPassword == "" {
4344
fmt.Println("WARNING: no password provided, private key will be saved in clear text")
4445
}
45-
err = generateKeyPair(*flCert, *flKey, *flPassword, *flForce)
46+
err = generateKeyPair(*flCert, *flKey, *flPassword, *flForce, *flCN, *flDays)
4647
if err == nil {
4748
fmt.Printf("wrote %s, %s\n", *flCert, *flKey)
4849
}
@@ -101,7 +102,7 @@ func decodeEncryptedKeyPEM(pemBytes []byte, password string) (*rsa.PrivateKey, e
101102
}
102103

103104
// generateKeyPair creates and saves a keypair checking whether they exist first.
104-
func generateKeyPair(certFile, keyFile, password string, force bool) error {
105+
func generateKeyPair(certFile, keyFile, password string, force bool, cn string, days int64) error {
105106
if !force {
106107
_, err := os.Stat(certFile)
107108
certExists := err == nil
@@ -111,7 +112,7 @@ func generateKeyPair(certFile, keyFile, password string, force bool) error {
111112
return errors.New("cert or key already exist, not overwriting")
112113
}
113114
}
114-
key, cert, err := tokenpki.SelfSignedRSAKeypair(defaultCN, defaultDays)
115+
key, cert, err := tokenpki.SelfSignedRSAKeypair(cn, days)
115116
if err != nil {
116117
return fmt.Errorf("generating keypair: %w", err)
117118
}

docs/openapi.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,19 @@ paths:
158158
description: Generate and store a new X.509 certificate and RSA private key (keypair) for exchanging the encrypted DEP OAuth1 tokens via the Apple ABM/ASM/BE portal. Each request generates a new (and overwrites the existing) keypair. The certificate is returned.
159159
security:
160160
- basicAuth: []
161+
parameters:
162+
- in: query
163+
name: cn
164+
required: false
165+
schema:
166+
type: string
167+
example: "depserver"
168+
- in: query
169+
name: validity_days
170+
required: false
171+
schema:
172+
type: integer
173+
example: 365
161174
responses:
162175
'200':
163176
description: X.509 certificate of the keypair used to encrypted the OAuth1 tokens.

docs/operations-guide.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ The `/v1/tokenpki/{name}` endpoints deal with the public key exchange using the
7777

7878
* Endpoint: `GET, PUT /v1/tokens/{name}`
7979

80-
The `/v1/tokens/{name} ` endpoints deal with the raw DEP OAuth tokens in JSON form. I.e. after the PKI exchange you can query for the actual DEP OAuth tokens if you like. This also allows configuring the OAuth1 tokens for a DEP name if you already have the tokens in JSON format. I.e. if you used the `deptokens` tool or you're using the DEP simulator `depsim`.
80+
The `/v1/tokens/{name}` endpoints deal with the raw DEP OAuth tokens in JSON form. I.e. after the PKI exchange you can query for the actual DEP OAuth tokens if you like. This also allows configuring the OAuth1 tokens for a DEP name if you already have the tokens in JSON format. I.e. if you used the `deptokens` tool or you're using the DEP simulator `depsim`.
8181

8282
#### Assigner
8383

@@ -169,10 +169,14 @@ The [Quickstart Guide](quickstart.md) also documents some usage of these scripts
169169
170170
For the DEP "MDM server" in the environment variable $DEP_NAME (see above) this script generates and retrieves the public key certificate for use when downloading the DEP authentication tokens from the ABM/ASM/BE portal. The `curl` call will dump the PEM-encoded certificate to stdout so you'll likely want to redirect it somewhere useful so it can be uploaded to the portal.
171171
172+
This script has two optional arguments:
173+
- The first argument specifies the Common Name to set in the certificate (default "depserver").
174+
- The second argument specifies the validity of the certificate in days (default 1 day).
175+
172176
##### Example usage
173177
174178
```bash
175-
$ ./tools/cfg-get-cert.sh > $DEP_NAME.pem
179+
$ ./tools/cfg-get-cert.sh depserver 365 > $DEP_NAME.pem
176180
% Total % Received % Xferd Average Speed Time Time Time Current
177181
Dload Upload Total Spent Left Speed
178182
100 1001 100 1001 0 0 4509 0 --:--:-- --:--:-- --:--:-- 4509
@@ -520,6 +524,18 @@ The file path to read or save the RSA private key that corresponds to the public
520524
521525
A password to encrypt or decrypt RSA private key on disk with. Note this is password is just to protect the private key itself and does not play a role in the token PKI exchange with Apple.
522526
527+
#### -cn
528+
529+
* common name to set in the certificate
530+
531+
A Common Name string to set in the certificate (default is "depserver").
532+
533+
#### -days
534+
535+
* validity of the generated certificate in days
536+
537+
The generated certificate will expire after the provided days.
538+
523539
#### -token string
524540
525541
* path to tokens

http/api/tokenpki.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"errors"
1010
"io"
1111
"net/http"
12+
"strconv"
1213

1314
"github.com/micromdm/nanodep/client"
1415
"github.com/micromdm/nanodep/log"
@@ -24,11 +25,6 @@ type TokenPKIStorer interface {
2425
StoreTokenPKI(context.Context, string, []byte, []byte) error
2526
}
2627

27-
const (
28-
defaultCN = "depserver"
29-
defaultDays = 1
30-
)
31-
3228
// PEMRSAPrivateKey returns key as a PEM block.
3329
func PEMRSAPrivateKey(key *rsa.PrivateKey) []byte {
3430
block := &pem.Block{
@@ -48,14 +44,36 @@ func PEMRSAPrivateKey(key *rsa.PrivateKey) []byte {
4844
// errors to the output as this is meant for "API" users.
4945
func GetCertTokenPKIHandler(store TokenPKIStorer, logger log.Logger) http.HandlerFunc {
5046
return func(w http.ResponseWriter, r *http.Request) {
47+
const (
48+
defaultCN = "depserver"
49+
defaultDays = 1
50+
)
5151
logger := ctxlog.Logger(r.Context(), logger)
5252
if r.URL.Path == "" {
5353
logger.Info("msg", "DEP name check", "err", "missing DEP name")
5454
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
5555
return
5656
}
5757
logger = logger.With("name", r.URL.Path)
58-
key, cert, err := tokenpki.SelfSignedRSAKeypair(defaultCN, defaultDays)
58+
var validityDays int64
59+
if daysArg := r.URL.Query().Get("validity_days"); daysArg == "" {
60+
logger.Debug("msg", "using default validity days", "days", defaultDays)
61+
validityDays = defaultDays
62+
} else {
63+
var err error
64+
validityDays, err = strconv.ParseInt(daysArg, 10, 64)
65+
if err != nil {
66+
logger.Info("msg", "validity_days check", "err", err)
67+
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
68+
return
69+
}
70+
}
71+
cn := r.URL.Query().Get("cn")
72+
if cn == "" {
73+
logger.Debug("msg", "using default CN", "cn", defaultCN)
74+
cn = defaultCN
75+
}
76+
key, cert, err := tokenpki.SelfSignedRSAKeypair(cn, validityDays)
5977
if err != nil {
6078
logger.Info("msg", "generating token keypair", "err", err)
6179
jsonError(w, err)

tokenpki/cert.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
// SelfSignedRSAKeypair generates a 2048-bit RSA private key and self-signs an
1515
// X.509 certificate using it. You can set the Common Name in cn and the
1616
// validity duration with days.
17-
func SelfSignedRSAKeypair(cn string, days int) (*rsa.PrivateKey, *x509.Certificate, error) {
17+
func SelfSignedRSAKeypair(cn string, days int64) (*rsa.PrivateKey, *x509.Certificate, error) {
1818
key, err := rsa.GenerateKey(rand.Reader, 2048)
1919
if err != nil {
2020
return nil, nil, err

tools/cfg-get-cert.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/sh
22

3-
URL="${BASE_URL}/v1/tokenpki/${DEP_NAME}"
3+
URL="${BASE_URL}/v1/tokenpki/${DEP_NAME}?cn=$1&validity_days=$2"
44

55
curl \
66
$CURL_OPTS \

0 commit comments

Comments
 (0)