// Get the public key matching a private key // TODO: Add support for non-RSA keys, switching on CKA_KEY_TYPE func getPublicKey(module ctx, session pkcs11.SessionHandle, privateKeyHandle pkcs11.ObjectHandle) (rsa.PublicKey, error) { var noKey rsa.PublicKey template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil), pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil), } attr, err := module.GetAttributeValue(session, privateKeyHandle, template) if err != nil { return noKey, err } n := big.NewInt(0) e := int(0) gotModulus, gotExponent := false, false for _, a := range attr { if a.Type == pkcs11.CKA_MODULUS { n.SetBytes(a.Value) gotModulus = true } else if a.Type == pkcs11.CKA_PUBLIC_EXPONENT { bigE := big.NewInt(0) bigE.SetBytes(a.Value) e = int(bigE.Int64()) gotExponent = true } } if !gotModulus || !gotExponent { return noKey, errors.New("public key missing either modulus or exponent") } return rsa.PublicKey{ N: n, E: e, }, nil }
func (ps *Key) getPrivateKey(module ctx, session pkcs11.SessionHandle, label string) (pkcs11.ObjectHandle, error) { var noHandle pkcs11.ObjectHandle template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_LABEL, label), } if err := module.FindObjectsInit(session, template); err != nil { return noHandle, err } objs, _, err := module.FindObjects(session, 2) if err != nil { return noHandle, err } if err = module.FindObjectsFinal(session); err != nil { return noHandle, err } if len(objs) == 0 { return noHandle, fmt.Errorf("private key not found") } privateKeyHandle := objs[0] // Check whether the key has the CKA_ALWAYS_AUTHENTICATE attribute. // If so, fail: we don't want to have to re-authenticate for each sign // operation. attributes, err := module.GetAttributeValue(session, privateKeyHandle, []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_ALWAYS_AUTHENTICATE, false), }) // The PKCS#11 spec states that C_GetAttributeValue may return // CKR_ATTRIBUTE_TYPE_INVALID if an object simply does not posses a given // attribute. We don't consider that an error: the absence of the // CKR_ATTRIBUTE_TYPE_INVALID property is just fine. if err != nil && err == pkcs11.Error(pkcs11.CKR_ATTRIBUTE_TYPE_INVALID) { return privateKeyHandle, nil } else if err != nil { return noHandle, err } for _, attribute := range attributes { if len(attribute.Value) > 0 && attribute.Value[0] == 1 { ps.alwaysAuthenticate = true } } return privateKeyHandle, nil }
func getKeyType(module ctx, session pkcs11.SessionHandle, privateKeyHandle pkcs11.ObjectHandle) (c byte, err error) { attributes, err := module.GetAttributeValue(session, privateKeyHandle, []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_KEY_TYPE, false), }) if err != nil { return } if (len(attributes) > 0) && (len(attributes[0].Value) > 0) { c = attributes[0].Value[0] } else { err = fmt.Errorf("No key type") } return }
// Get the public key matching an Elliptic Curve private key func getECPublicKey(module ctx, session pkcs11.SessionHandle, privateKeyHandle pkcs11.ObjectHandle) (crypto.PublicKey, error) { var noKey interface{} // http://docs.oasis-open.org/pkcs11/pkcs11-curr/v2.40/os/pkcs11-curr-v2.40-os.html#_Toc416960012 template := []*pkcs11.Attribute{ // CKA_EC_PARAMS contains the OID of the curve (part of the // public key pkcs11.NewAttribute(pkcs11.CKA_EC_PARAMS, nil), // CKA_ID will allow use to find the corresponding public key pkcs11.NewAttribute(pkcs11.CKA_ID, nil), } attr, err := module.GetAttributeValue(session, privateKeyHandle, template) if err != nil { return noKey, err } oid := []byte{} id := []byte{} gotOid, gotID := false, false for _, a := range attr { if a.Type == pkcs11.CKA_EC_PARAMS { oid = a.Value gotOid = true } else if a.Type == pkcs11.CKA_ID { id = a.Value gotID = true } } if !gotOid { return noKey, errors.New("private key missing curve parameters") } if !gotID { return noKey, errors.New("private key missing identifier (CKA_ID)") } poid := new(asn1.ObjectIdentifier) asn1.Unmarshal(oid, poid) curve := namedCurveFromOID(*poid) templateSearch := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PUBLIC_KEY), pkcs11.NewAttribute(pkcs11.CKA_ID, id), } if err := module.FindObjectsInit(session, templateSearch); err != nil { return noKey, err } objs, _, err := module.FindObjects(session, 1) if err != nil { return noKey, err } if err = module.FindObjectsFinal(session); err != nil { return noKey, err } if len(objs) == 0 { return noKey, fmt.Errorf("public key not found") } publicKeyHandle := objs[0] templatePub := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_EC_POINT, nil), } attrPub, err := module.GetAttributeValue(session, publicKeyHandle, templatePub) if err != nil { return noKey, err } ecPoint := []byte{} gotEcPoint := false for _, a := range attrPub { if a.Type == pkcs11.CKA_EC_POINT { ecPoint = a.Value gotEcPoint = true } } if !gotEcPoint { return noKey, errors.New("public key missing EC Point") } x, y := readECPoint(curve, ecPoint) if x == nil { return noKey, errors.New("invalid EC Point") } ecdsa := ecdsa.PublicKey{ Curve: curve, X: x, Y: y, } return &ecdsa, nil }
// New instantiates a new handle to a PKCS #11-backed key. func New(module, tokenLabel, pin, privLabel string, slotID int) (ps *PKCS11Key, err error) { // Set up a new pkcs11 object and initialize it p := pkcs11.New(module) if p == nil { err = errors.New("unable to load PKCS#11 module") return } if err = p.Initialize(); err != nil { return } // Initialize a partial key ps = &PKCS11Key{ module: p, slotID: slotID, tokenLabel: tokenLabel, pin: pin, } // Look up the private key session, err := ps.openSession() if err != nil { ps.Destroy() return } defer ps.closeSession(session) template := []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY), pkcs11.NewAttribute(pkcs11.CKA_LABEL, privLabel), } if err = p.FindObjectsInit(session, template); err != nil { ps.Destroy() return } objs, _, err := p.FindObjects(session, 2) if err != nil { ps.Destroy() return } if err = p.FindObjectsFinal(session); err != nil { ps.Destroy() return } if len(objs) == 0 { err = errors.New("private key not found") ps.Destroy() return } ps.privateKeyHandle = objs[0] // Populate the pubic key from the private key // TODO: Add support for non-RSA keys, switching on CKA_KEY_TYPE template = []*pkcs11.Attribute{ pkcs11.NewAttribute(pkcs11.CKA_MODULUS, nil), pkcs11.NewAttribute(pkcs11.CKA_PUBLIC_EXPONENT, nil), } attr, err := p.GetAttributeValue(session, ps.privateKeyHandle, template) if err != nil { ps.Destroy() return } n := big.NewInt(0) e := int(0) gotModulus, gotExponent := false, false for _, a := range attr { if a.Type == pkcs11.CKA_MODULUS { n.SetBytes(a.Value) gotModulus = true } else if a.Type == pkcs11.CKA_PUBLIC_EXPONENT { bigE := big.NewInt(0) bigE.SetBytes(a.Value) e = int(bigE.Int64()) gotExponent = true } } if !gotModulus || !gotExponent { ps.Destroy() return } ps.publicKey = rsa.PublicKey{ N: n, E: e, } return }