// Sign performs a signature using the PKCS #11 key. func (ps *PKCS11Key) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { // Verify that the length of the hash is as expected hash := opts.HashFunc() hashLen := hash.Size() if len(msg) != hashLen { err = errors.New("input size does not match hash function output size") return } // Add DigestInfo prefix // TODO: Switch mechanisms based on CKA_KEY_TYPE mechanism := []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS, nil)} prefix, ok := hashPrefixes[hash] if !ok { err = errors.New("unknown hash function") return } signatureInput := append(prefix, msg...) // Open a session session, err := ps.openSession() if err != nil { return } defer ps.closeSession(session) // Perform the sign operation err = ps.module.SignInit(session, mechanism, ps.privateKeyHandle) if err != nil { return } signature, err = ps.module.Sign(session, signatureInput) return }
// Sign performs a signature using the PKCS #11 key. func (ps *Key) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) (signature []byte, err error) { ps.sessionMu.Lock() defer ps.sessionMu.Unlock() if ps.session == nil { return nil, errors.New("Session was nil") } // When the alwaysAuthenticate bit is true (e.g. on a Yubikey NEO in PIV mode), // each Sign has to include a Logout/Login, or the next Sign request will get // CKR_USER_NOT_LOGGED_IN. This is very slow, but on the NEO it's not possible // to clear the CKA_ALWAYS_AUTHENTICATE bit, so this is the only available // workaround. // Also, since logged in / logged out is application state rather than session // state, we take a global lock while we do the logout and login, and during // the signing. if ps.alwaysAuthenticate { modulesMu.Lock() defer modulesMu.Unlock() if err := ps.module.Logout(*ps.session); err != nil { return nil, fmt.Errorf("logout: %s", err) } if err = ps.module.Login(*ps.session, pkcs11.CKU_USER, ps.pin); err != nil { return nil, fmt.Errorf("login: %s", err) } } // Verify that the length of the hash is as expected hash := opts.HashFunc() hashLen := hash.Size() if len(msg) != hashLen { err = fmt.Errorf("input size does not match hash function output size: %d vs %d", len(msg), hashLen) return } // Add DigestInfo prefix // TODO: Switch mechanisms based on CKA_KEY_TYPE mechanism := []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_RSA_PKCS, nil)} prefix, ok := hashPrefixes[hash] if !ok { err = errors.New("unknown hash function") return } signatureInput := append(prefix, msg...) // Perform the sign operation err = ps.module.SignInit(*ps.session, mechanism, ps.privateKeyHandle) if err != nil { return nil, fmt.Errorf("sign init: %s", err) } signature, err = ps.module.Sign(*ps.session, signatureInput) if err != nil { return nil, fmt.Errorf("sign: %s", err) } return }