1 #include <openssl/evp.h>
5 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
6 #include <boost/assign/list_of.hpp>
8 #include <boost/format.hpp>
9 #include <p11-kit/p11-kit.h>
11 #include "pdns/dnssecinfra.hh"
12 #include "pdns/logger.hh"
13 #include "pdns/pdnsexception.hh"
14 #include "pdns/sha.hh"
15 #include "pdns/lock.hh"
17 #ifdef HAVE_LIBCRYPTO_ECDSA
18 #include <openssl/bn.h>
19 #include <openssl/ec.h>
23 #include "pkcs11signers.hh"
26 - list possible tokens and supported modes
27 - Engine: <name>, Slot: <slot>, PIN: <pin>
28 - ECDSA support (how to test?)
30 NB! If you do use this, here is a simple way to get softhsm working
32 create /etc/pkcs11/modules/softhsm.module
36 module: /usr/lib/softhsm/libsofthsm.so
39 in it. you need to use softhsm tools to manage this all.
43 #ifdef HAVE_P11KIT1_V2
44 static CK_FUNCTION_LIST
** p11_modules
;
47 static constexpr const char* ECDSA256_PARAMS
{"\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"};
48 static constexpr const char* ECDSA384_PARAMS
{"\x06\x05\x2b\x81\x04\x00\x22"};
50 // map for signing algorithms
51 static std::map
<unsigned int,CK_MECHANISM_TYPE
> dnssec2smech
= boost::assign::map_list_of
52 (5, CKM_SHA1_RSA_PKCS
)
53 (7, CKM_SHA1_RSA_PKCS
)
54 (8, CKM_SHA256_RSA_PKCS
)
55 (10, CKM_SHA512_RSA_PKCS
)
59 // map for hashing algorithms
60 static std::map
<unsigned int,CK_MECHANISM_TYPE
> dnssec2hmech
= boost::assign::map_list_of
68 static std::map
<unsigned int,CK_MECHANISM_TYPE
> dnssec2cmech
= boost::assign::map_list_of
69 (5, CKM_RSA_PKCS_KEY_PAIR_GEN
)
70 (7, CKM_RSA_PKCS_KEY_PAIR_GEN
)
71 (8, CKM_RSA_PKCS_KEY_PAIR_GEN
)
72 (10, CKM_RSA_PKCS_KEY_PAIR_GEN
)
73 (13, CKM_ECDSA_KEY_PAIR_GEN
)
74 (14, CKM_ECDSA_KEY_PAIR_GEN
);
76 using CkaValueType
= enum { Attribute_Byte
, Attribute_Long
, Attribute_String
};
79 class P11KitAttribute
{
81 CK_ATTRIBUTE_TYPE type
;
86 std::unique_ptr
<unsigned char[]> buffer
;
93 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, const std::string
& value
) {
99 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, char value
) {
105 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, unsigned char value
) {
111 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, unsigned long value
) {
117 [[nodiscard
]] CkaValueType
valueType() const {
121 [[nodiscard
]] const std::string
&str() const {
125 [[nodiscard
]] unsigned char byte() const {
129 [[nodiscard
]] unsigned long ulong() const {
133 void setString(const std::string
& value
) {
134 this->ckString
= value
;
135 this->ckType
= Attribute_String
;
138 void setByte(char value
) {
139 this->ckByte
= value
;
140 this->ckType
= Attribute_Byte
;
143 void setByte(unsigned char value
) {
144 this->ckByte
= value
;
145 this->ckType
= Attribute_Byte
;
148 void setLong(unsigned long value
) {
149 this->ckLong
= value
;
150 this->ckType
= Attribute_Long
;
153 // this bit is used for getting attribute from object
154 // we provide a pointer for GetAttributeValue to write to
155 CK_BYTE_PTR
allocate(CK_ULONG amount
) {
156 buffer
= std::make_unique
<unsigned char[]>(amount
);
161 // and here we copy the results back and delete buffer
162 void commit(CK_ULONG amount
) {
164 this->ckString
.assign((char*)buffer
.get(), amount
);
170 // this is *writable* attribute (you write into it)
171 void wattr(CK_ATTRIBUTE_PTR attr
) {
174 case Attribute_Byte
: {
175 attr
->pValue
= (void*)&ckByte
;
176 attr
->ulValueLen
= 1;
179 case Attribute_Long
: {
180 attr
->pValue
= (void*)&ckLong
;
181 attr
->ulValueLen
= sizeof(CK_ULONG
);
184 case Attribute_String
: {
185 attr
->pValue
= buffer
.get();
186 attr
->ulValueLen
= buflen
;
191 // this is *readable* attribute (you read from it)
192 void rattr(CK_ATTRIBUTE_PTR attr
) const {
195 case Attribute_Byte
: {
196 attr
->pValue
= (void*)&ckByte
;
197 attr
->ulValueLen
= 1;
200 case Attribute_Long
: {
201 attr
->pValue
= (void*)&ckLong
;
202 attr
->ulValueLen
= sizeof(CK_ULONG
);
205 case Attribute_String
: {
206 attr
->pValue
= (void*)ckString
.c_str();
207 attr
->ulValueLen
= ckString
.size();
217 CK_FUNCTION_LIST
* d_functions
; // module functions
218 CK_SESSION_HANDLE d_session
;
223 void logError(const std::string
& operation
) const {
225 std::string msg
= boost::str( boost::format("PKCS#11 operation %s failed: %s (0x%X) (%s)") % operation
% p11_kit_strerror(d_err
) % d_err
% p11_kit_message() );
226 g_log
<<Logger::Error
<< msg
<< endl
;
231 Pkcs11Slot(CK_FUNCTION_LIST
* functions
, const CK_SLOT_ID
& slot
) :
233 d_functions(functions
),
237 CK_TOKEN_INFO tokenInfo
;
239 if ((d_err
= d_functions
->C_OpenSession(this->d_slot
, CKF_SERIAL_SESSION
|CKF_RW_SESSION
, 0, 0, &(this->d_session
)))) {
240 logError("C_OpenSession");
241 throw PDNSException("Could not open session");
243 // check if we need to login
244 if ((d_err
= d_functions
->C_GetTokenInfo(d_slot
, &tokenInfo
)) == 0) {
245 d_logged_in
= !((tokenInfo
.flags
& CKF_LOGIN_REQUIRED
) == CKF_LOGIN_REQUIRED
);
247 logError("C_GetTokenInfo");
248 throw PDNSException("Cannot get token info for slot " + std::to_string(slot
));
252 bool Login(const std::string
& pin
, CK_USER_TYPE userType
=CKU_USER
) {
253 if (userType
== CKU_USER
&& d_logged_in
) {
257 auto uPin
= std::make_unique
<unsigned char[]>(pin
.size());
258 memcpy(uPin
.get(), pin
.c_str(), pin
.size());
259 d_err
= d_functions
->C_Login(this->d_session
, userType
, uPin
.get(), pin
.size());
262 if (d_err
== 0 && userType
== CKU_USER
) {
271 return Login(d_pin
, CKU_CONTEXT_SPECIFIC
);
274 bool LoggedIn() const { return d_logged_in
; }
276 CK_SESSION_HANDLE
& Session() { return d_session
; }
278 CK_FUNCTION_LIST
* f() { return d_functions
; }
280 static std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> GetSlot(const std::string
& module
, const string
& tokenId
);
281 static CK_RV
HuntSlot(const string
& tokenId
, CK_SLOT_ID
&slotId
, _CK_SLOT_INFO
* info
, CK_FUNCTION_LIST
* functions
);
286 std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> d_slot
;
288 CK_OBJECT_HANDLE d_public_key
{0};
289 CK_OBJECT_HANDLE d_private_key
{0};
290 CK_KEY_TYPE d_key_type
{0};
291 bool d_always_auth
{false};
294 std::string d_exponent
;
295 std::string d_modulus
;
296 std::string d_ec_point
;
297 std::string d_ecdsa_params
;
300 std::string d_pub_label
;
305 void logError(const std::string
& operation
) const {
307 std::string msg
= boost::str( boost::format("PKCS#11 operation %s failed: %s (0x%X) (%s)") % operation
% p11_kit_strerror(d_err
) % d_err
% p11_kit_message());
308 g_log
<<Logger::Error
<< msg
<< endl
;
312 [[nodiscard
]] unsigned int ecparam2bits(const std::string
& obj
) const {
313 // if we can use some library to parse the EC parameters, better use it.
314 // otherwise fall back to using hardcoded primev256 and secp384r1
315 #ifdef HAVE_LIBCRYPTO_ECDSA
316 #if OPENSSL_VERSION_MAJOR >= 3
317 using Key
= std::unique_ptr
<EVP_PKEY
, decltype(&EVP_PKEY_free
)>;
319 using Key
= std::unique_ptr
<EC_KEY
, decltype(&EC_KEY_free
)>;
320 using BigNum
= std::unique_ptr
<BIGNUM
, decltype(&BN_clear_free
)>;
323 unsigned int bits
= 0;
325 // NOLINTNEXTLINE(*-cast): Using OpenSSL C APIs.
326 const auto* objCStr
= reinterpret_cast<const unsigned char*>(obj
.c_str());
327 #if OPENSSL_VERSION_MAJOR >= 3
328 auto key
= Key(d2i_KeyParams(EVP_PKEY_EC
, nullptr, &objCStr
, static_cast<long>(obj
.size())), EVP_PKEY_free
);
330 auto key
= Key(d2i_ECParameters(nullptr, &objCStr
, static_cast<long>(obj
.size())), EC_KEY_free
);
332 if (key
== nullptr) {
333 throw pdns::OpenSSL::error("PKCS11", "Cannot parse EC parameters from DER");
336 #if OPENSSL_VERSION_MAJOR >= 3
337 bits
= EVP_PKEY_get_bits(key
.get());
339 const auto* group
= EC_KEY_get0_group(key
.get());
340 auto order
= BigNum(BN_new(), BN_clear_free
);
341 if (EC_GROUP_get_order(group
, order
.get(), nullptr) == 1) {
342 bits
= BN_num_bits(order
.get());
347 throw PDNSException("Unsupported EC key");
352 if (d_ecdsa_params
== ECDSA256_PARAMS
) return 256;
353 else if (d_ecdsa_params
== ECDSA384_PARAMS
) return 384;
354 else throw PDNSException("Unsupported EC key");
359 Pkcs11Token(const std::shared_ptr
<LockGuarded
<Pkcs11Slot
>>& slot
, const std::string
& label
, const std::string
& pub_label
);
362 bool Login(const std::string
& pin
) {
363 if (pin
.empty()) return false; // no empty pin.
364 if (d_slot
->lock()->Login(pin
) == true) {
372 if (d_loaded
== false && d_slot
->lock()->LoggedIn() == true) {
375 return d_slot
->lock()->LoggedIn();
378 void LoadAttributes() {
379 auto slot
= d_slot
->lock();
380 std::vector
<P11KitAttribute
> attr
;
381 std::vector
<CK_OBJECT_HANDLE
> key
;
382 attr
.emplace_back(CKA_CLASS
, (unsigned long)CKO_PRIVATE_KEY
);
383 attr
.emplace_back(CKA_LABEL
, d_label
);
384 FindObjects2(*slot
, attr
, key
, 1);
385 if (key
.size() == 0) {
386 g_log
<<Logger::Warning
<<"Cannot load PKCS#11 private key "<<d_label
<<std::endl
;;
389 d_private_key
= key
[0];
391 attr
.emplace_back(CKA_ALWAYS_AUTHENTICATE
, '\0');
392 if (GetAttributeValue2(*slot
, d_private_key
, attr
)==0) {
393 d_always_auth
= attr
[0].byte() != 0;
396 attr
.emplace_back(CKA_CLASS
, (unsigned long)CKO_PUBLIC_KEY
);
397 attr
.emplace_back(CKA_LABEL
, d_pub_label
);
398 FindObjects2(*slot
, attr
, key
, 1);
399 if (key
.size() == 0) {
400 g_log
<<Logger::Warning
<<"Cannot load PKCS#11 public key "<<d_pub_label
<<std::endl
;
403 d_public_key
= key
[0];
406 attr
.emplace_back(CKA_KEY_TYPE
, 0UL);
408 if (GetAttributeValue2(*slot
, d_public_key
, attr
)==0) {
409 d_key_type
= attr
[0].ulong();
410 if (d_key_type
== CKK_RSA
) {
412 attr
.emplace_back(CKA_MODULUS
, "");
413 attr
.emplace_back(CKA_PUBLIC_EXPONENT
, "");
414 attr
.emplace_back(CKA_MODULUS_BITS
, 0UL);
416 if (!GetAttributeValue2(*slot
, d_public_key
, attr
)) {
417 d_modulus
= attr
[0].str();
418 d_exponent
= attr
[1].str();
419 d_bits
= attr
[2].ulong();
421 throw PDNSException("Cannot load attributes for PKCS#11 public key " + d_pub_label
);
423 } else if (d_key_type
== CKK_EC
|| d_key_type
== CKK_ECDSA
) {
425 attr
.emplace_back(CKA_ECDSA_PARAMS
, "");
426 attr
.emplace_back(CKA_EC_POINT
, "");
427 if (!GetAttributeValue2(*slot
, d_public_key
, attr
)) {
428 d_ecdsa_params
= attr
[0].str();
429 d_bits
= ecparam2bits(d_ecdsa_params
);
430 if (attr
[1].str().length() != (d_bits
*2/8 + 3)) throw PDNSException("EC Point data invalid");
431 d_ec_point
= attr
[1].str().substr(3);
433 throw PDNSException("Cannot load attributes for PKCS#11 public key " + d_pub_label
);
436 throw PDNSException("Cannot determine type for PKCS#11 public key " + d_pub_label
);
439 throw PDNSException("Cannot load attributes for PKCS#11 public key " + d_pub_label
);
445 int GenerateKeyPair(CK_MECHANISM_PTR mechanism
, std::vector
<P11KitAttribute
>& pubAttributes
, std::vector
<P11KitAttribute
>& privAttributes
, CK_OBJECT_HANDLE_PTR pubKey
, CK_OBJECT_HANDLE_PTR privKey
) {
447 auto slot
= d_slot
->lock();
450 auto pubAttr
= std::make_unique
<CK_ATTRIBUTE
[]>(pubAttributes
.size());
451 auto privAttr
= std::make_unique
<CK_ATTRIBUTE
[]>(privAttributes
.size());
454 for(P11KitAttribute
& attribute
: pubAttributes
) {
455 attribute
.rattr(pubAttr
.get()+k
);
460 for(P11KitAttribute
& attribute
: privAttributes
) {
461 attribute
.rattr(privAttr
.get()+k
);
465 d_err
= slot
->f()->C_GenerateKeyPair(slot
->Session(), mechanism
, pubAttr
.get(), pubAttributes
.size(), privAttr
.get(), privAttributes
.size(), pubKey
, privKey
);
466 logError("C_GenerateKeyPair");
469 if (d_err
== 0) LoadAttributes();
474 int Sign(const std::string
& data
, std::string
& result
, CK_MECHANISM_PTR mechanism
) {
475 CK_BYTE buffer
[1024];
476 CK_ULONG buflen
= sizeof buffer
; // should be enough for most signatures.
477 auto slot
= d_slot
->lock();
479 if ((d_err
= slot
->f()->C_SignInit(slot
->Session(), mechanism
, d_private_key
))) { logError("C_SignInit"); return d_err
; }
480 // check if we need to relogin
485 d_err
= slot
->f()->C_Sign(slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), buffer
, &buflen
);
488 result
.assign((char*)buffer
, buflen
);
491 memset(buffer
,0,sizeof buffer
);
496 int Verify(const std::string
& data
, const std::string
& signature
, CK_MECHANISM_PTR mechanism
) {
497 auto slot
= d_slot
->lock();
499 if ((d_err
= slot
->f()->C_VerifyInit(slot
->Session(), mechanism
, d_public_key
))) { logError("C_VerifyInit"); return d_err
; }
500 // check if we need to relogin
505 d_err
= slot
->f()->C_Verify(slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), (unsigned char*)signature
.c_str(), signature
.size());
506 logError("C_Verify");
510 int Digest(const std::string
& data
, std::string
& result
, CK_MECHANISM_PTR mechanism
) {
511 CK_BYTE buffer
[1024];
512 CK_ULONG buflen
= sizeof buffer
; // should be enough for most digests
514 auto slot
= d_slot
->lock();
515 if ((d_err
= slot
->f()->C_DigestInit(slot
->Session(), mechanism
))) { logError("C_DigestInit"); return d_err
; }
516 d_err
= slot
->f()->C_Digest(slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), buffer
, &buflen
);
518 result
.assign((char*)buffer
, buflen
);
520 memset(buffer
,0,sizeof buffer
);
521 logError("C_Digest");
525 int DigestInit(Pkcs11Slot
& slot
, CK_MECHANISM_PTR mechanism
) {
526 d_err
= slot
.f()->C_DigestInit(slot
.Session(), mechanism
);
527 logError("C_DigestInit");
531 int DigestUpdate(Pkcs11Slot
& slot
, const std::string
& data
) {
532 d_err
= slot
.f()->C_DigestUpdate(slot
.Session(), (unsigned char*)data
.c_str(), data
.size());
533 logError("C_DigestUpdate");
537 int DigestFinal(Pkcs11Slot
& slot
, std::string
& result
) {
538 CK_BYTE buffer
[1024] = {0};
539 CK_ULONG buflen
= sizeof buffer
; // should be enough for most digests
541 d_err
= slot
.f()->C_DigestFinal(slot
.Session(), buffer
, &buflen
);
543 result
.assign((char*)buffer
, buflen
);
545 memset(buffer
,0,sizeof buffer
);
546 logError("C_DigestFinal");
550 int FindObjects2(Pkcs11Slot
& slot
, const std::vector
<P11KitAttribute
>& attributes
, std::vector
<CK_OBJECT_HANDLE
>& objects
, int maxobjects
) {
555 auto handles
= std::make_unique
<CK_OBJECT_HANDLE
[]>(maxobjects
);
556 auto attr
= std::make_unique
<CK_ATTRIBUTE
[]>(attributes
.size());
559 for(const P11KitAttribute
& attribute
: attributes
) {
560 attribute
.rattr(attr
.get()+k
);
565 d_err
= slot
.f()->C_FindObjectsInit(slot
.Session(), attr
.get(), k
);
568 logError("C_FindObjectsInit");
573 rv
= d_err
= slot
.f()->C_FindObjects(slot
.Session(), handles
.get(), maxobjects
, &count
);
577 for(k
=0;k
<count
;k
++) {
578 objects
.push_back((handles
.get())[k
]);
582 logError("C_FindObjects");
584 d_err
= slot
.f()->C_FindObjectsFinal(slot
.Session());
585 logError("C_FindObjectsFinal");
590 int GetAttributeValue2(Pkcs11Slot
& slot
, const CK_OBJECT_HANDLE
& object
, std::vector
<P11KitAttribute
>& attributes
)
593 auto attr
= std::make_unique
<CK_ATTRIBUTE
[]>(attributes
.size());
596 for(P11KitAttribute
&attribute
: attributes
) {
597 attribute
.wattr(attr
.get()+k
);
601 // round 1 - get attribute sizes
602 d_err
= slot
.f()->C_GetAttributeValue(slot
.Session(), object
, attr
.get(), attributes
.size());
603 logError("C_GetAttributeValue");
608 // then allocate memory
609 for(size_t idx
=0; idx
< attributes
.size(); idx
++) {
610 if (attributes
[idx
].valueType() == Attribute_String
) {
611 (attr
.get())[idx
].pValue
= attributes
[idx
].allocate((attr
.get())[idx
].ulValueLen
);
615 // round 2 - get actual values
616 d_err
= slot
.f()->C_GetAttributeValue(slot
.Session(), object
, attr
.get(), attributes
.size());
617 logError("C_GetAttributeValue");
619 // copy values to map and release allocated memory
620 for(size_t idx
=0; idx
< attributes
.size(); idx
++) {
621 if (attributes
[idx
].valueType() == Attribute_String
) {
622 attributes
[idx
].commit((attr
.get())[idx
].ulValueLen
);
629 const std::string
& Modulus() {
633 const std::string
& Exponent() {
637 const std::string
& ECPoint() {
641 const std::string
& ECParameters() {
642 return d_ecdsa_params
;
645 CK_KEY_TYPE
KeyType() {
653 static std::shared_ptr
<Pkcs11Token
> GetToken(const std::string
& module
, const string
& tokenId
, const std::string
& label
, const std::string
& pub_label
);
656 static std::map
<std::string
, std::shared_ptr
<LockGuarded
<Pkcs11Slot
> > > pkcs11_slots
;
657 static std::map
<std::string
, std::shared_ptr
<Pkcs11Token
> > pkcs11_tokens
;
659 CK_RV
Pkcs11Slot::HuntSlot(const string
& tokenId
, CK_SLOT_ID
&slotId
, _CK_SLOT_INFO
* info
, CK_FUNCTION_LIST
* functions
)
664 _CK_TOKEN_INFO tinfo
;
667 // this is required by certain tokens, otherwise C_GetSlotInfo will not return a token
668 err
= functions
->C_GetSlotList(CK_FALSE
, NULL_PTR
, &slots
);
670 g_log
<<Logger::Warning
<<"C_GetSlotList(CK_FALSE, NULL_PTR, &slots) = " << err
<< std::endl
;
674 // get the actual slot ids
675 std::vector
<CK_SLOT_ID
> slotIds(slots
);
676 err
= functions
->C_GetSlotList(CK_FALSE
, slotIds
.data(), &slots
);
678 g_log
<<Logger::Warning
<<"C_GetSlotList(CK_FALSE, slotIds, &slots) = " << err
<< std::endl
;
683 for(i
=0;i
<slots
;i
++) {
685 if (slotId
== static_cast<CK_SLOT_ID
>(-1))
687 if ((err
= functions
->C_GetSlotInfo(slotId
, info
))) {
688 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", info) = " << err
<< std::endl
;
691 if ((err
= functions
->C_GetTokenInfo(slotId
, &tinfo
))) {
692 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", &tinfo) = " << err
<< std::endl
;
695 std::string slotName
;
696 slotName
.assign(reinterpret_cast<char*>(tinfo
.label
), 32);
698 boost::trim(slotName
);
700 if (boost::iequals(slotName
, tokenId
)) {
705 // see if we can find it with slotId
707 slotId
= std::stoi(tokenId
);
708 if ((err
= functions
->C_GetSlotInfo(slotId
, info
))) {
709 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", info) = " << err
<< std::endl
;
712 g_log
<<Logger::Warning
<<"Specifying PKCS#11 token by SLOT ID is deprecated and should not be used"<<std::endl
;
715 return CKR_SLOT_ID_INVALID
;
717 return CKR_SLOT_ID_INVALID
;
720 std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> Pkcs11Slot::GetSlot(const std::string
& module
, const string
& tokenId
) {
721 // see if we can find module
722 std::string sidx
= module
;
724 sidx
.append(tokenId
);
725 std::map
<std::string
, std::shared_ptr
<LockGuarded
<Pkcs11Slot
> > >::iterator slotIter
;
727 CK_FUNCTION_LIST
* functions
;
729 // see if we have slot
730 if ((slotIter
= pkcs11_slots
.find(sidx
)) != pkcs11_slots
.end()) {
731 return slotIter
->second
;
734 #ifdef HAVE_P11KIT1_V2
735 functions
= p11_kit_module_for_name(p11_modules
, module
.c_str());
737 functions
= p11_kit_registered_name_to_module(module
.c_str());
739 if (functions
== nullptr) throw PDNSException("Cannot find PKCS#11 module " + module
);
740 functions
->C_Initialize(nullptr); // initialize the module in case it hasn't been done yet.
742 // try to locate a slot
746 if ((err
= Pkcs11Slot::HuntSlot(tokenId
, slotId
, &info
, functions
))) {
747 throw PDNSException(std::string("Cannot find PKCS#11 token ") + tokenId
+ std::string(" on module ") + module
+ std::string(": ") + boost::str( boost::format("%s (0x%X)") % p11_kit_strerror(err
) % err
));
751 pkcs11_slots
[sidx
] = std::make_shared
<LockGuarded
<Pkcs11Slot
>>(Pkcs11Slot(functions
, slotId
));
753 return pkcs11_slots
[sidx
];
756 std::shared_ptr
<Pkcs11Token
> Pkcs11Token::GetToken(const std::string
& module
, const string
& tokenId
, const std::string
& label
, const std::string
& pub_label
) {
757 // see if we can find module
758 std::string tidx
= module
;
760 tidx
.append(tokenId
);
763 std::map
<std::string
, std::shared_ptr
<Pkcs11Token
> >::iterator tokenIter
;
764 if ((tokenIter
= pkcs11_tokens
.find(tidx
)) != pkcs11_tokens
.end()) return tokenIter
->second
;
766 std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> slot
= Pkcs11Slot::GetSlot(module
, tokenId
);
767 pkcs11_tokens
[tidx
] = std::make_shared
<Pkcs11Token
>(slot
, label
, pub_label
);
768 return pkcs11_tokens
[tidx
];
771 Pkcs11Token::Pkcs11Token(const std::shared_ptr
<LockGuarded
<Pkcs11Slot
>>& slot
, const std::string
& label
, const std::string
& pub_label
) :
775 d_pub_label(pub_label
),
780 if (this->d_slot
->lock()->LoggedIn()) LoadAttributes();
783 Pkcs11Token::~Pkcs11Token() = default;
785 bool PKCS11ModuleSlotLogin(const std::string
& module
, const string
& tokenId
, const std::string
& pin
)
787 std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> slot
= Pkcs11Slot::GetSlot(module
, tokenId
);
788 if (slot
->lock()->LoggedIn()) return true; // no point failing
789 return slot
->lock()->Login(pin
);
792 PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(unsigned int algorithm
): DNSCryptoKeyEngine(algorithm
) {}
793 PKCS11DNSCryptoKeyEngine::~PKCS11DNSCryptoKeyEngine() = default;
794 PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(const PKCS11DNSCryptoKeyEngine
& orig
) : DNSCryptoKeyEngine(orig
.d_algorithm
) {}
796 void PKCS11DNSCryptoKeyEngine::create(unsigned int bits
) {
797 std::vector
<P11KitAttribute
> pubAttr
;
798 std::vector
<P11KitAttribute
> privAttr
;
800 CK_OBJECT_HANDLE pubKey
, privKey
;
801 std::shared_ptr
<Pkcs11Token
> d_slot
;
802 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
803 if (d_slot
->LoggedIn() == false)
804 if (d_slot
->Login(d_pin
) == false)
805 throw PDNSException("Not logged in to token");
807 std::string
pubExp("\000\001\000\001", 4); // 65537
810 mech
.mechanism
= dnssec2cmech
.at(d_algorithm
);
811 } catch (std::out_of_range
& e
) {
812 throw PDNSException("pkcs11: unsupported algorithm "+std::to_string(d_algorithm
)+ " for key pair generation");
815 mech
.pParameter
= nullptr;
816 mech
.ulParameterLen
= 0;
818 if (mech
.mechanism
== CKM_RSA_PKCS_KEY_PAIR_GEN
) {
819 pubAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PUBLIC_KEY
));
820 pubAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_RSA
));
821 pubAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
822 pubAttr
.push_back(P11KitAttribute(CKA_ENCRYPT
, (char)CK_TRUE
));
823 pubAttr
.push_back(P11KitAttribute(CKA_VERIFY
, (char)CK_TRUE
));
824 pubAttr
.push_back(P11KitAttribute(CKA_WRAP
, (char)CK_TRUE
));
825 pubAttr
.push_back(P11KitAttribute(CKA_MODULUS_BITS
, (unsigned long)bits
));
826 pubAttr
.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT
, pubExp
));
827 pubAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_pub_label
));
829 privAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PRIVATE_KEY
));
830 privAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_RSA
));
831 privAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
832 privAttr
.push_back(P11KitAttribute(CKA_PRIVATE
, (char)CK_TRUE
));
833 // privAttr.push_back(P11KitAttribute(CKA_SUBJECT, "CN=keygen"));
834 privAttr
.push_back(P11KitAttribute(CKA_ID
, "\x01\x02\x03\x04")); // this is mandatory if you want to export anything
835 privAttr
.push_back(P11KitAttribute(CKA_SENSITIVE
, (char)CK_TRUE
));
836 privAttr
.push_back(P11KitAttribute(CKA_DECRYPT
, (char)CK_TRUE
));
837 privAttr
.push_back(P11KitAttribute(CKA_SIGN
, (char)CK_TRUE
));
838 privAttr
.push_back(P11KitAttribute(CKA_UNWRAP
, (char)CK_TRUE
));
839 privAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_label
));
840 } else if (mech
.mechanism
== CKM_ECDSA_KEY_PAIR_GEN
) {
841 pubAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PUBLIC_KEY
));
842 pubAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_ECDSA
));
843 pubAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
844 pubAttr
.push_back(P11KitAttribute(CKA_ENCRYPT
, (char)CK_TRUE
));
845 pubAttr
.push_back(P11KitAttribute(CKA_VERIFY
, (char)CK_TRUE
));
846 pubAttr
.push_back(P11KitAttribute(CKA_WRAP
, (char)CK_TRUE
));
847 pubAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_pub_label
));
848 if (d_algorithm
== 13) pubAttr
.push_back(P11KitAttribute(CKA_ECDSA_PARAMS
, ECDSA256_PARAMS
));
849 else if (d_algorithm
== 14) pubAttr
.push_back(P11KitAttribute(CKA_ECDSA_PARAMS
, ECDSA384_PARAMS
));
850 else throw PDNSException("pkcs11: unknown algorithm "+std::to_string(d_algorithm
)+" for ECDSA key pair generation");
852 privAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PRIVATE_KEY
));
853 privAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_ECDSA
));
854 privAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
855 privAttr
.push_back(P11KitAttribute(CKA_PRIVATE
, (char)CK_TRUE
));
856 // privAttr.push_back(P11KitAttribute(CKA_SUBJECT, "CN=keygen"));
857 privAttr
.push_back(P11KitAttribute(CKA_ID
, "\x01\x02\x03\x04")); // this is mandatory if you want to export anything
858 privAttr
.push_back(P11KitAttribute(CKA_SENSITIVE
, (char)CK_TRUE
));
859 privAttr
.push_back(P11KitAttribute(CKA_DECRYPT
, (char)CK_TRUE
));
860 privAttr
.push_back(P11KitAttribute(CKA_SIGN
, (char)CK_TRUE
));
861 privAttr
.push_back(P11KitAttribute(CKA_UNWRAP
, (char)CK_TRUE
));
862 privAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_label
));
864 throw PDNSException("pkcs11: don't know how make key for algorithm "+std::to_string(d_algorithm
));
868 if (d_slot
->GenerateKeyPair(&mech
, pubAttr
, privAttr
, &pubKey
, &privKey
)) {
869 throw PDNSException("Keypair generation failed");
873 std::string
PKCS11DNSCryptoKeyEngine::sign(const std::string
& msg
) const {
875 std::shared_ptr
<Pkcs11Token
> d_slot
;
876 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
877 if (d_slot
->LoggedIn() == false)
878 if (d_slot
->Login(d_pin
) == false)
879 throw PDNSException("Not logged in to token");
882 mech
.mechanism
= dnssec2smech
[d_algorithm
];
883 mech
.pParameter
= nullptr;
884 mech
.ulParameterLen
= 0;
886 if (mech
.mechanism
== CKM_ECDSA
) {
887 if (d_slot
->Sign(this->hash(msg
), result
, &mech
)) throw PDNSException("Could not sign data");
889 if (d_slot
->Sign(msg
, result
, &mech
)) throw PDNSException("Could not sign data");
894 std::string
PKCS11DNSCryptoKeyEngine::hash(const std::string
& msg
) const {
897 mech
.mechanism
= dnssec2hmech
[d_algorithm
];
898 mech
.pParameter
= nullptr;
899 mech
.ulParameterLen
= 0;
900 std::shared_ptr
<Pkcs11Token
> d_slot
;
901 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
902 if (d_slot
->LoggedIn() == false)
903 if (d_slot
->Login(d_pin
) == false)
904 throw PDNSException("Not logged in to token");
906 if (d_slot
->Digest(msg
, result
, &mech
)) {
907 g_log
<<Logger::Error
<<"Could not digest using PKCS#11 token - using software workaround"<<endl
;
908 // FINE! I'll do this myself, then, shall I?
909 switch(d_algorithm
) {
911 return pdns::sha1sum(msg
);
914 return pdns::sha256sum(msg
);
917 return pdns::sha512sum(msg
);
920 return pdns::sha256sum(msg
);
923 return pdns::sha384sum(msg
);
930 bool PKCS11DNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const {
931 std::shared_ptr
<Pkcs11Token
> d_slot
;
932 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
933 if (d_slot
->LoggedIn() == false)
934 if (d_slot
->Login(d_pin
) == false)
935 throw PDNSException("Not logged in to token");
938 mech
.mechanism
= dnssec2smech
[d_algorithm
];
939 mech
.pParameter
= nullptr;
940 mech
.ulParameterLen
= 0;
941 if (mech
.mechanism
== CKM_ECDSA
) {
942 return (d_slot
->Verify(this->hash(msg
), signature
, &mech
)==0);
944 return (d_slot
->Verify(msg
, signature
, &mech
) == 0);
948 std::string
PKCS11DNSCryptoKeyEngine::getPublicKeyString() const {
949 std::string
result("");
950 std::shared_ptr
<Pkcs11Token
> d_slot
;
951 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
952 if (d_slot
->LoggedIn() == false)
953 if (d_slot
->Login(d_pin
) == false)
954 throw PDNSException("Not logged in to token");
956 if (d_slot
->KeyType() == CKK_RSA
) {
957 if (d_slot
->Exponent().length() < 255) {
958 result
.assign(1, (char) (unsigned int) d_slot
->Exponent().length());
961 uint16_t len
=htons(d_slot
->Exponent().length());
962 result
.append((char*)&len
, 2);
964 result
.append(d_slot
->Exponent());
965 result
.append(d_slot
->Modulus());
967 result
.append(d_slot
->ECPoint());
972 int PKCS11DNSCryptoKeyEngine::getBits() const {
973 std::shared_ptr
<Pkcs11Token
> d_slot
;
974 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
975 if (d_slot
->LoggedIn() == false)
976 if (d_slot
->Login(d_pin
) == false)
977 throw PDNSException("Not logged in to token");
979 return d_slot
->Bits();
982 DNSCryptoKeyEngine::storvector_t
PKCS11DNSCryptoKeyEngine::convertToISCVector() const {
983 auto storvect
= storvector_t
{
984 {"Algorithm", std::to_string(d_algorithm
)},
985 {"Engine", d_module
},
989 {"PubLabel", d_pub_label
},
994 void PKCS11DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, stormap_t
& stormap
) {
995 pdns::checked_stoi_into(drc
.d_algorithm
, stormap
["algorithm"]);
996 d_module
= stormap
["engine"];
997 d_slot_id
= stormap
["slot"];
998 boost::trim(d_slot_id
);
999 d_pin
= stormap
["pin"];
1000 d_label
= stormap
["label"];
1001 if (stormap
.find("publabel") != stormap
.end())
1002 d_pub_label
= stormap
["publabel"];
1004 d_pub_label
= d_label
;
1005 // validate parameters
1007 std::shared_ptr
<Pkcs11Token
> d_slot
;
1008 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
1009 if (d_pin
!= "" && d_slot
->LoggedIn() == false)
1010 if (d_slot
->Login(d_pin
) == false)
1011 throw PDNSException("Could not log in to token (PIN wrong?)");
1014 std::unique_ptr
<DNSCryptoKeyEngine
> PKCS11DNSCryptoKeyEngine::maker(unsigned int algorithm
)
1016 return make_unique
<PKCS11DNSCryptoKeyEngine
>(algorithm
);
1019 // this is called during program startup
1021 static struct LoaderStruct
1025 #ifdef HAVE_P11KIT1_V2
1026 p11_modules
= p11_kit_modules_load_and_initialize(0);
1028 p11_kit_initialize_registered();
1032 #ifdef HAVE_P11KIT1_V2
1033 p11_kit_modules_release(p11_modules
);
1035 p11_kit_finalize_registered();