forked from letsencrypt/boulder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rsa.go
98 lines (92 loc) · 3.62 KB
/
rsa.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package main
import (
"crypto/rsa"
"errors"
"log"
"math/big"
"github.com/letsencrypt/boulder/pkcs11helpers"
"github.com/miekg/pkcs11"
)
const (
rsaExp = 65537
)
// rsaArgs constructs the private and public key template attributes sent to the
// device and specifies which mechanism should be used. modulusLen specifies the
// length of the modulus to be generated on the device in bits and exponent
// specifies the public exponent that should be used.
func rsaArgs(label string, modulusLen, exponent uint, keyID []byte) generateArgs {
// Encode as unpadded big endian encoded byte slice
expSlice := big.NewInt(int64(exponent)).Bytes()
log.Printf("\tEncoded public exponent (%d) as: %0X\n", exponent, expSlice)
return generateArgs{
mechanism: []*pkcs11.Mechanism{
pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS_KEY_PAIR_GEN, nil),
},
publicAttrs: []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_ID, keyID),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
// Allow the key to verify signatures
pkcs11.NewAttribute(pkcs11.CKA_VERIFY, true),
// Set requested modulus length
pkcs11.NewAttribute(pkcs11.CKA_MODULUS_BITS, modulusLen),
// Set requested public exponent
pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, expSlice),
},
privateAttrs: []*pkcs11.Attribute{
pkcs11.NewAttribute(pkcs11.CKA_ID, keyID),
pkcs11.NewAttribute(pkcs11.CKA_LABEL, label),
pkcs11.NewAttribute(pkcs11.CKA_TOKEN, true),
// Prevent attributes being retrieved
pkcs11.NewAttribute(pkcs11.CKA_SENSITIVE, true),
// Prevent the key being extracted from the device
pkcs11.NewAttribute(pkcs11.CKA_EXTRACTABLE, false),
// Allow the key to create signatures
pkcs11.NewAttribute(pkcs11.CKA_SIGN, true),
},
}
}
// rsaPub extracts the generated public key, specified by the provided object
// handle, and constructs a rsa.PublicKey. It also checks that the key has the
// correct length modulus and that the public exponent is what was requested in
// the public key template.
func rsaPub(session *pkcs11helpers.Session, object pkcs11.ObjectHandle, modulusLen, exponent uint) (*rsa.PublicKey, error) {
pubKey, err := session.GetRSAPublicKey(object)
if err != nil {
return nil, err
}
if pubKey.E != int(exponent) {
return nil, errors.New("returned CKA_PUBLIC_EXPONENT doesn't match expected exponent")
}
if pubKey.N.BitLen() != int(modulusLen) {
return nil, errors.New("returned CKA_MODULUS isn't of the expected bit length")
}
log.Printf("\tPublic exponent: %d\n", pubKey.E)
log.Printf("\tModulus: (%d bits) %X\n", pubKey.N.BitLen(), pubKey.N.Bytes())
return pubKey, nil
}
// rsaGenerate is used to generate and verify a RSA key pair of the size
// specified by modulusLen and with the exponent 65537.
// It returns the public part of the generated key pair as a rsa.PublicKey
// and the random key ID that the HSM uses to identify the key pair.
func rsaGenerate(session *pkcs11helpers.Session, label string, modulusLen uint) (*rsa.PublicKey, []byte, error) {
keyID := make([]byte, 4)
_, err := newRandReader(session).Read(keyID)
if err != nil {
return nil, nil, err
}
log.Printf("Generating RSA key with %d bit modulus and public exponent %d and ID %x\n", modulusLen, rsaExp, keyID)
args := rsaArgs(label, modulusLen, rsaExp, keyID)
pub, _, err := session.GenerateKeyPair(args.mechanism, args.publicAttrs, args.privateAttrs)
if err != nil {
return nil, nil, err
}
log.Println("Key generated")
log.Println("Extracting public key")
pk, err := rsaPub(session, pub, modulusLen, rsaExp)
if err != nil {
return nil, nil, err
}
log.Println("Extracted public key")
return pk, keyID, nil
}