Skip to content

Commit

Permalink
Merge pull request #15 from maditya/ec-p11
Browse files Browse the repository at this point in the history
add support for signing with ECDSA P256 key
  • Loading branch information
maditya authored Jul 1, 2019
2 parents d44fbbd + ba0b3fc commit 1693898
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 40 deletions.
73 changes: 54 additions & 19 deletions docker-softhsm/crypki.conf.sample
Original file line number Diff line number Diff line change
@@ -1,21 +1,56 @@
{
"ModulePath": "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so",
"SSHUserInfo": {"KeyLabel": "user_ssh", "SlotNumber": SLOTNUM_USER_SSH, "UserPinPath" : "/dev/shm/slot_pwd.txt"},
"X509Info": {"KeyLabel": "host_x509", "SlotNumber": SLOTNUM_HOST_X509, "UserPinPath" : "/dev/shm/slot_pwd.txt"},
"SSHHostInfo": {"KeyLabel": "host_ssh", "SlotNumber": SLOTNUM_HOST_SSH, "UserPinPath" : "/dev/shm/slot_pwd.txt"},
"TLSServerName": "localhost",
"TLSClientAuthMode": 4,
"TLSServerCertPath": "/opt/crypki/tls-crt/server.crt",
"TLSServerKeyPath": "/opt/crypki/tls-crt/server.key",
"TLSCACertPath": "/opt/crypki/tls-crt/ca.crt",
"Keys": [
{"Identifier": "ssh-user-key", "KeyLabel": "user_ssh", "SlotNumber": SLOTNUM_USER_SSH, "UserPinPath" : "/dev/shm/slot_pwd.txt"},
{"Identifier": "x509-key", "KeyLabel": "host_x509", "SlotNumber": SLOTNUM_HOST_X509, "UserPinPath" : "/dev/shm/slot_pwd.txt", "X509CACertLocation": "/opt/crypki/x509_ca.crt", "CreateCACertIfNotExist": true, "Country": "US", "State": "Some-State", "Locality": "Example", "Organization": "Example! Inc.", "OrganizationalUnit": "Example"},
{"Identifier": "ssh-host-key", "KeyLabel": "host_ssh", "SlotNumber": SLOTNUM_HOST_SSH, "UserPinPath" : "/dev/shm/slot_pwd.txt"}
],
"KeyUsages": [
{"Endpoint": "/sig/ssh-user-cert", "Identifiers": ["ssh-user-key"]},
{"Endpoint": "/sig/x509-cert", "Identifiers": ["x509-key"]},
{"Endpoint": "/sig/ssh-host-cert", "Identifiers": ["ssh-host-key"]}
]
"KeyUsages": [
{
"Endpoint": "/sig/ssh-user-cert",
"Identifiers": [
"ssh-user-key"
]
},
{
"Endpoint": "/sig/x509-cert",
"Identifiers": [
"x509-key"
]
},
{
"Endpoint": "/sig/ssh-host-cert",
"Identifiers": [
"ssh-host-key"
]
}
],
"Keys": [
{
"Identifier": "ssh-user-key",
"KeyLabel": "user_ssh",
"SlotNumber": SLOTNUM_USER_SSH,
"UserPinPath": "/dev/shm/slot_pwd.txt"
},
{
"Country": "US",
"CreateCACertIfNotExist": true,
"Identifier": "x509-key",
"KeyLabel": "host_x509",
"KeyType": 2,
"Locality": "Example",
"Organization": "Example! Inc.",
"OrganizationalUnit": "Example",
"SlotNumber": SLOTNUM_HOST_X509,
"State": "Some-State",
"UserPinPath": "/dev/shm/slot_pwd.txt",
"X509CACertLocation": "/opt/crypki/x509_ca.crt"
},
{
"Identifier": "ssh-host-key",
"KeyLabel": "host_ssh",
"SlotNumber": SLOTNUM_HOST_SSH,
"UserPinPath": "/dev/shm/slot_pwd.txt"
}
],
"ModulePath": "/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so",
"TLSCACertPath": "/opt/crypki/tls-crt/ca.crt",
"TLSClientAuthMode": 4,
"TLSServerCertPath": "/opt/crypki/tls-crt/server.crt",
"TLSServerKeyPath": "/opt/crypki/tls-crt/server.key",
"TLSServerName": "localhost"
}
28 changes: 18 additions & 10 deletions docker-softhsm/init_hsm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,32 @@ error() {
SOPIN=1234
USERPIN=123456

modulepath="/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so"

user_ssh_label="user_ssh"
host_x509_label="host_x509"
host_ssh_label="host_ssh"
user_ssh_keytype="rsa:4096"
host_x509_keytype="EC:prime256v1"
host_ssh_keytype="rsa:4096"

#
# check for needed binaries/etc, provide "helpful" advice
# check for required binaries and libraries
#
if [ "`uname -s`" != "Linux" ]; then
error "This only works on linux because the binaries and librarys are only available there."
error "This only works on linux because required binaries and libraries are only available and tested on linux."
fi
p11tool="`which pkcs11-tool 2>/dev/null`"
p11tool="${p11tool:=/usr/bin/pkcs11-tool}"
if [ ! -x "${p11tool}" ]; then
error "Can't find pkcs11-tool binary in path or /usr/bin/pkcs11-tool. Needed to configure the HSM.
yum -y install opensc # (or local equivalent rpm)"
error "Can't find pkcs11-tool binary in path or /usr/bin/pkcs11-tool. Needed to configure the HSM/PKCS#11 device.
yum -y install opensc or apt-get install opensc # (or local equivalent package)"
fi
softhsm="`which softhsm2-util 2>/dev/null`"
softhsm="${softhsm:=/usr/bin/softhsm2-util}"
if [ ! -x "${softhsm}" ]; then
error "Can't find softhsm binary in path or /usr/bin/softhsm2-util. Needed to configure the HSM.
yum -y install softhsm # (or local equivalent rpm)"
error "Can't find softhsm binary in path or /usr/bin/softhsm2-util. Needed to configure the HSM/PKCS#11 device.
yum -y install softhsm or apt-get install softhsm # (or local equivalent package)"
fi

set -e # exit if anything at all fails after here
Expand All @@ -38,11 +47,10 @@ user_ssh_slot=`${softhsm} --init-token --slot 0 --label user_ssh --so-pin ${SOPI
host_x509_slot=`${softhsm} --init-token --slot 1 --label host_x509 --so-pin ${SOPIN} --pin ${USERPIN} | awk '{print $NF}'`
host_ssh_slot=`${softhsm} --init-token --slot 2 --label host_ssh --so-pin ${SOPIN} --pin ${USERPIN} | awk '{print $NF}'`

modulepath="/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so"
# Generate the Keys in the PKCS11 slot
${p11tool} --module ${modulepath} --pin 123456 --slot ${user_ssh_slot} --keypairgen --label "user_ssh" --key-type rsa:4096 --private
${p11tool} --module ${modulepath} --pin 123456 --slot ${host_x509_slot} --keypairgen --label "host_x509" --key-type rsa:4096 --private
${p11tool} --module ${modulepath} --pin 123456 --slot ${host_ssh_slot} --keypairgen --label "host_ssh" --key-type rsa:4096 --private
${p11tool} --module ${modulepath} --pin ${USERPIN} --slot ${user_ssh_slot} --keypairgen --label ${user_ssh_label} --key-type ${user_ssh_keytype} --private
${p11tool} --module ${modulepath} --pin ${USERPIN} --slot ${host_x509_slot} --keypairgen --label ${host_x509_label} --key-type ${host_x509_keytype} --private
${p11tool} --module ${modulepath} --pin ${USERPIN} --slot ${host_ssh_slot} --keypairgen --label ${host_ssh_label} --key-type ${host_ssh_keytype} --private

CRYPKI_CONFIG=`sed -e "s/SLOTNUM_USER_SSH/${user_ssh_slot}/g; s/SLOTNUM_HOST_X509/${host_x509_slot}/g; s/SLOTNUM_HOST_SSH/${host_ssh_slot}/g" crypki.conf.sample`

Expand Down
124 changes: 120 additions & 4 deletions pkcs11/ecdsa.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,133 @@ package pkcs11

import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"encoding/asn1"
"errors"
"fmt"
"math/big"

p11 "github.com/miekg/pkcs11"
)

// Representation of a *DSA signature
type dsaSignature struct {
R, S *big.Int
}

// oidDERToCurve maps the hex of the DER encoding of the various curve OIDs to
// the relevant curve parameters
var oidDERToCurve = map[string]*elliptic.CurveParams{
"06052B81040021": elliptic.P224().Params(),
"06082A8648CE3D030107": elliptic.P256().Params(),
"06052B81040022": elliptic.P384().Params(),
"06052B81040023": elliptic.P521().Params(),
}

func getPublic(point []byte) (pub crypto.PublicKey, err error) {
var ecdsaPub ecdsa.PublicKey

ecdsaPub.Curve = elliptic.P256() // TODO: allow other curves
pointLength := ecdsaPub.Curve.Params().BitSize/8*2 + 1
if len(point) != pointLength {
err = fmt.Errorf("CKA_EC_POINT (%d) does not fit used curve (%d)", len(point), pointLength)
return
}
ecdsaPub.X, ecdsaPub.Y = elliptic.Unmarshal(ecdsaPub.Curve, point[:pointLength])
if ecdsaPub.X == nil {
err = fmt.Errorf("failed to decode CKA_EC_POINT")
return
}
if !ecdsaPub.Curve.IsOnCurve(ecdsaPub.X, ecdsaPub.Y) {
err = fmt.Errorf("public key is not on curve")
return
}

pub = &ecdsaPub
return
}

func publicECDSA(s *p11Signer) crypto.PublicKey {
// TODO: implement
panic("not implemented yet")
// Retrieve the curve and public point for the generated public key
attrs, err := s.context.GetAttributeValue(s.session, s.publicKey, []*p11.Attribute{
p11.NewAttribute(p11.CKA_EC_PARAMS, nil),
p11.NewAttribute(p11.CKA_EC_POINT, nil),
})
if len(attrs) < 2 {
panic("expected two attributes")
}

/*
// TODO: use this to make it work for other curves
cur, ok := oidDERToCurve[fmt.Sprintf("%X", attrs[0].Value)]
if !ok {
panic("unknown curve")
}
*/
pointBytes := attrs[1].Value
if pointBytes == nil {
panic("unable to get EC point")
}
var pb []byte
_, err = asn1.Unmarshal(pointBytes, &pb)
if err != nil {
panic("asn1 unmarshal failed: " + err.Error())
}
pubkey, err := getPublic(pb)
if err != nil {
panic("getPublic failed: " + err.Error())
}
return pubkey
}

func signDataECDSA(ctx PKCS11Ctx, session p11.SessionHandle, hsmPrivateObject p11.ObjectHandle, data []byte, opts crypto.SignerOpts) ([]byte, error) {
// TODO: implement
return nil, errors.New("not implemented yet")
const MAXBYTES = 262042
if len(data) > MAXBYTES {
return nil, errors.New("Cannot sign such a large blob of data")
}

privateKeyHandle := hsmPrivateObject

// We only support SHA1, SHA256, SHA384 and SHA512 hash digest algorithms.
hash := opts.HashFunc()
mech := make([]*p11.Mechanism, 1)
switch hash {
case crypto.SHA1, crypto.SHA256, crypto.SHA384, crypto.SHA512:
mech[0] = p11.NewMechanism(p11.CKM_ECDSA, nil)
default:
return nil, errors.New("Unsupported hash algorithm")
}

err := ctx.SignInit(session, mech, privateKeyHandle)
if err != nil {
return nil, err
}
sigBytes, err := ctx.Sign(session, data)
if err != nil {
return nil, err
}
var sig dsaSignature
err = sig.unmarshalBytes(sigBytes)
if err != nil {
return nil, err
}
return sig.marshalDER()
}

// Return the DER encoding of a dsaSignature
func (sig *dsaSignature) marshalDER() ([]byte, error) {
return asn1.Marshal(*sig)
}

// Populate a dsaSignature from a raw byte sequence
func (sig *dsaSignature) unmarshalBytes(sigBytes []byte) error {
if len(sigBytes) == 0 || len(sigBytes)%2 != 0 {
return errors.New("malformed signature")
}
n := len(sigBytes) / 2
sig.R, sig.S = new(big.Int), new(big.Int)
sig.R.SetBytes(sigBytes[:n])
sig.S.SetBytes(sigBytes[n:])
return nil
}
Loading

0 comments on commit 1693898

Please sign in to comment.