4 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
5 #include <boost/assign/list_of.hpp>
7 #include <boost/format.hpp>
8 #include <p11-kit/p11-kit.h>
10 #include "pdns/dnssecinfra.hh"
11 #include "pdns/logger.hh"
12 #include "pdns/pdnsexception.hh"
13 #include "pdns/sha.hh"
14 #include "pdns/lock.hh"
16 #ifdef HAVE_LIBCRYPTO_ECDSA
17 #include <openssl/bn.h>
18 #include <openssl/ec.h>
21 #include "pkcs11signers.hh"
24 - list possible tokens and supported modes
25 - Engine: <name>, Slot: <slot>, PIN: <pin>
26 - ECDSA support (how to test?)
28 NB! If you do use this, here is a simple way to get softhsm working
30 create /etc/pkcs11/modules/softhsm.module
34 module: /usr/lib/softhsm/libsofthsm.so
37 in it. you need to use softhsm tools to manage this all.
41 #ifdef HAVE_P11KIT1_V2
42 static CK_FUNCTION_LIST
** p11_modules
;
45 #define ECDSA256_PARAMS "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"
46 #define ECDSA384_PARAMS "\x06\x05\x2b\x81\x04\x00\x22"
48 // map for signing algorithms
49 static std::map
<unsigned int,CK_MECHANISM_TYPE
> dnssec2smech
= boost::assign::map_list_of
50 (5, CKM_SHA1_RSA_PKCS
)
51 (7, CKM_SHA1_RSA_PKCS
)
52 (8, CKM_SHA256_RSA_PKCS
)
53 (10, CKM_SHA512_RSA_PKCS
)
57 // map for hashing algorithms
58 static std::map
<unsigned int,CK_MECHANISM_TYPE
> dnssec2hmech
= boost::assign::map_list_of
66 static std::map
<unsigned int,CK_MECHANISM_TYPE
> dnssec2cmech
= boost::assign::map_list_of
67 (5, CKM_RSA_PKCS_KEY_PAIR_GEN
)
68 (7, CKM_RSA_PKCS_KEY_PAIR_GEN
)
69 (8, CKM_RSA_PKCS_KEY_PAIR_GEN
)
70 (10, CKM_RSA_PKCS_KEY_PAIR_GEN
)
71 (13, CKM_ECDSA_KEY_PAIR_GEN
)
72 (14, CKM_ECDSA_KEY_PAIR_GEN
);
74 typedef enum { Attribute_Byte
, Attribute_Long
, Attribute_String
} CkaValueType
;
77 class P11KitAttribute
{
79 CK_ATTRIBUTE_TYPE type
;
84 std::unique_ptr
<unsigned char[]> buffer
;
91 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, const std::string
& value
) {
97 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, char value
) {
103 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, unsigned char value
) {
109 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, unsigned long value
) {
115 CkaValueType
valueType() const {
119 const std::string
&str() const {
123 unsigned char byte() const {
127 unsigned long ulong() const {
131 void setString(const std::string
& value
) {
132 this->ckString
= value
;
133 this->ckType
= Attribute_String
;
136 void setByte(char value
) {
137 this->ckByte
= value
;
138 this->ckType
= Attribute_Byte
;
141 void setByte(unsigned char value
) {
142 this->ckByte
= value
;
143 this->ckType
= Attribute_Byte
;
146 void setLong(unsigned long value
) {
147 this->ckLong
= value
;
148 this->ckType
= Attribute_Long
;
151 // this bit is used for getting attribute from object
152 // we provide a pointer for GetAttributeValue to write to
153 CK_BYTE_PTR
allocate(CK_ULONG amount
) {
154 buffer
= std::make_unique
<unsigned char[]>(amount
);
159 // and here we copy the results back and delete buffer
160 void commit(CK_ULONG amount
) {
162 this->ckString
.assign((char*)buffer
.get(), amount
);
168 // this is *writable* attribute (you write into it)
169 void wattr(CK_ATTRIBUTE_PTR attr
) {
172 case Attribute_Byte
: {
173 attr
->pValue
= (void*)&ckByte
;
174 attr
->ulValueLen
= 1;
177 case Attribute_Long
: {
178 attr
->pValue
= (void*)&ckLong
;
179 attr
->ulValueLen
= sizeof(CK_ULONG
);
182 case Attribute_String
: {
183 attr
->pValue
= buffer
.get();
184 attr
->ulValueLen
= buflen
;
189 // this is *readable* attribute (you read from it)
190 void rattr(CK_ATTRIBUTE_PTR attr
) const {
193 case Attribute_Byte
: {
194 attr
->pValue
= (void*)&ckByte
;
195 attr
->ulValueLen
= 1;
198 case Attribute_Long
: {
199 attr
->pValue
= (void*)&ckLong
;
200 attr
->ulValueLen
= sizeof(CK_ULONG
);
203 case Attribute_String
: {
204 attr
->pValue
= (void*)ckString
.c_str();
205 attr
->ulValueLen
= ckString
.size();
215 CK_FUNCTION_LIST
* d_functions
; // module functions
216 CK_SESSION_HANDLE d_session
;
220 void logError(const std::string
& operation
) const {
222 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() );
223 g_log
<<Logger::Error
<< msg
<< endl
;
228 Pkcs11Slot(CK_FUNCTION_LIST
* functions
, const CK_SLOT_ID
& slot
) :
230 d_functions(functions
),
234 CK_TOKEN_INFO tokenInfo
;
236 if ((d_err
= d_functions
->C_OpenSession(this->d_slot
, CKF_SERIAL_SESSION
|CKF_RW_SESSION
, 0, 0, &(this->d_session
)))) {
237 logError("C_OpenSession");
238 throw PDNSException("Could not open session");
240 // check if we need to login
241 if ((d_err
= d_functions
->C_GetTokenInfo(d_slot
, &tokenInfo
)) == 0) {
242 d_logged_in
= !((tokenInfo
.flags
& CKF_LOGIN_REQUIRED
) == CKF_LOGIN_REQUIRED
);
244 logError("C_GetTokenInfo");
245 throw PDNSException("Cannot get token info for slot " + std::to_string(slot
));
249 bool Login(const std::string
& pin
) {
250 if (d_logged_in
) return true;
252 auto uPin
= std::make_unique
<unsigned char[]>(pin
.size());
253 memcpy(uPin
.get(), pin
.c_str(), pin
.size());
254 d_err
= d_functions
->C_Login(this->d_session
, CKU_USER
, uPin
.get(), pin
.size());
255 memset(uPin
.get(), 0, pin
.size());
265 bool LoggedIn() const { return d_logged_in
; }
267 CK_SESSION_HANDLE
& Session() { return d_session
; }
269 CK_FUNCTION_LIST
* f() { return d_functions
; }
271 static std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> GetSlot(const std::string
& module
, const string
& tokenId
);
272 static CK_RV
HuntSlot(const string
& tokenId
, CK_SLOT_ID
&slotId
, _CK_SLOT_INFO
* info
, CK_FUNCTION_LIST
* functions
);
277 std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> d_slot
;
279 CK_OBJECT_HANDLE d_public_key
;
280 CK_OBJECT_HANDLE d_private_key
;
281 CK_KEY_TYPE d_key_type
;
284 std::string d_exponent
;
285 std::string d_modulus
;
286 std::string d_ec_point
;
287 std::string d_ecdsa_params
;
290 std::string d_pub_label
;
295 void logError(const std::string
& operation
) const {
297 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());
298 g_log
<<Logger::Error
<< msg
<< endl
;
302 unsigned int ecparam2bits(const std::string
& obj
) const {
303 // if we can use some library to parse the EC parameters, better use it.
304 // otherwise fall back to using hardcoded primev256 and secp384r1
305 #ifdef HAVE_LIBCRYPTO_ECDSA
306 unsigned int bits
= 0;
307 const unsigned char *in
= reinterpret_cast<const unsigned char*>(obj
.c_str());
308 auto order
= std::unique_ptr
<BIGNUM
, void(*)(BIGNUM
*)>(BN_new(), BN_clear_free
);
309 auto tempKey
= d2i_ECParameters(nullptr, &in
, obj
.size());
310 if (tempKey
!= nullptr) {
311 auto key
= std::unique_ptr
<EC_KEY
, void(*)(EC_KEY
*)>(tempKey
, EC_KEY_free
);
313 if (EC_GROUP_get_order(EC_KEY_get0_group(key
.get()), order
.get(), nullptr) == 1) {
314 bits
= BN_num_bits(order
.get());
319 throw PDNSException("Unsupported EC key");
323 if (d_ecdsa_params
== ECDSA256_PARAMS
) return 256;
324 else if (d_ecdsa_params
== ECDSA384_PARAMS
) return 384;
325 else throw PDNSException("Unsupported EC key");
330 Pkcs11Token(const std::shared_ptr
<LockGuarded
<Pkcs11Slot
>>& slot
, const std::string
& label
, const std::string
& pub_label
);
333 bool Login(const std::string
& pin
) {
334 if (pin
.empty()) return false; // no empty pin.
335 if (d_slot
->lock()->Login(pin
) == true) {
343 if (d_loaded
== false && d_slot
->lock()->LoggedIn() == true) {
346 return d_slot
->lock()->LoggedIn();
349 void LoadAttributes() {
350 auto slot
= d_slot
->lock();
351 std::vector
<P11KitAttribute
> attr
;
352 std::vector
<CK_OBJECT_HANDLE
> key
;
353 attr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PRIVATE_KEY
));
354 // attr.push_back(P11KitAttribute(CKA_SIGN, (char)CK_TRUE));
355 attr
.push_back(P11KitAttribute(CKA_LABEL
, d_label
));
356 FindObjects2(*slot
, attr
, key
, 1);
357 if (key
.size() == 0) {
358 g_log
<<Logger::Warning
<<"Cannot load PCKS#11 private key "<<d_label
<<std::endl
;;
361 d_private_key
= key
[0];
363 attr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PUBLIC_KEY
));
364 // attr.push_back(P11KitAttribute(CKA_VERIFY, (char)CK_TRUE));
365 attr
.push_back(P11KitAttribute(CKA_LABEL
, d_pub_label
));
366 FindObjects2(*slot
, attr
, key
, 1);
367 if (key
.size() == 0) {
368 g_log
<<Logger::Warning
<<"Cannot load PCKS#11 public key "<<d_pub_label
<<std::endl
;
371 d_public_key
= key
[0];
374 attr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, 0UL));
376 if (GetAttributeValue2(*slot
, d_public_key
, attr
)==0) {
377 d_key_type
= attr
[0].ulong();
378 if (d_key_type
== CKK_RSA
) {
380 attr
.push_back(P11KitAttribute(CKA_MODULUS
, ""));
381 attr
.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT
, ""));
382 attr
.push_back(P11KitAttribute(CKA_MODULUS_BITS
, 0UL));
384 if (!GetAttributeValue2(*slot
, d_public_key
, attr
)) {
385 d_modulus
= attr
[0].str();
386 d_exponent
= attr
[1].str();
387 d_bits
= attr
[2].ulong();
389 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label
);
391 } else if (d_key_type
== CKK_EC
|| d_key_type
== CKK_ECDSA
) {
393 attr
.push_back(P11KitAttribute(CKA_ECDSA_PARAMS
, ""));
394 attr
.push_back(P11KitAttribute(CKA_EC_POINT
, ""));
395 if (!GetAttributeValue2(*slot
, d_public_key
, attr
)) {
396 d_ecdsa_params
= attr
[0].str();
397 d_bits
= ecparam2bits(d_ecdsa_params
);
398 if (attr
[1].str().length() != (d_bits
*2/8 + 3)) throw PDNSException("EC Point data invalid");
399 d_ec_point
= attr
[1].str().substr(3);
401 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label
);
404 throw PDNSException("Cannot determine type for PCKS#11 public key " + d_pub_label
);
407 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label
);
413 int GenerateKeyPair(CK_MECHANISM_PTR mechanism
, std::vector
<P11KitAttribute
>& pubAttributes
, std::vector
<P11KitAttribute
>& privAttributes
, CK_OBJECT_HANDLE_PTR pubKey
, CK_OBJECT_HANDLE_PTR privKey
) {
415 auto slot
= d_slot
->lock();
418 auto pubAttr
= std::make_unique
<CK_ATTRIBUTE
[]>(pubAttributes
.size());
419 auto privAttr
= std::make_unique
<CK_ATTRIBUTE
[]>(pubAttributes
.size());
422 for(P11KitAttribute
& attribute
: pubAttributes
) {
423 attribute
.rattr(pubAttr
.get()+k
);
428 for(P11KitAttribute
& attribute
: privAttributes
) {
429 attribute
.rattr(privAttr
.get()+k
);
433 d_err
= slot
->f()->C_GenerateKeyPair(slot
->Session(), mechanism
, pubAttr
.get(), pubAttributes
.size(), privAttr
.get(), privAttributes
.size(), pubKey
, privKey
);
434 logError("C_GenerateKeyPair");
437 if (d_err
== 0) LoadAttributes();
442 int Sign(const std::string
& data
, std::string
& result
, CK_MECHANISM_PTR mechanism
) {
443 CK_BYTE buffer
[1024];
444 CK_ULONG buflen
= sizeof buffer
; // should be enough for most signatures.
445 auto slot
= d_slot
->lock();
448 if ((d_err
= slot
->f()->C_SignInit(slot
->Session(), mechanism
, d_private_key
))) { logError("C_SignInit"); return d_err
; }
449 d_err
= slot
->f()->C_Sign(slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), buffer
, &buflen
);
452 result
.assign((char*)buffer
, buflen
);
455 memset(buffer
,0,sizeof buffer
);
460 int Verify(const std::string
& data
, const std::string
& signature
, CK_MECHANISM_PTR mechanism
) {
461 auto slot
= d_slot
->lock();
463 if ((d_err
= slot
->f()->C_VerifyInit(slot
->Session(), mechanism
, d_public_key
))) { logError("C_VerifyInit"); return d_err
; }
464 d_err
= slot
->f()->C_Verify(slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), (unsigned char*)signature
.c_str(), signature
.size());
465 logError("C_Verify");
469 int Digest(const std::string
& data
, std::string
& result
, CK_MECHANISM_PTR mechanism
) {
470 CK_BYTE buffer
[1024];
471 CK_ULONG buflen
= sizeof buffer
; // should be enough for most digests
473 auto slot
= d_slot
->lock();
474 if ((d_err
= slot
->f()->C_DigestInit(slot
->Session(), mechanism
))) { logError("C_DigestInit"); return d_err
; }
475 d_err
= slot
->f()->C_Digest(slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), buffer
, &buflen
);
477 result
.assign((char*)buffer
, buflen
);
479 memset(buffer
,0,sizeof buffer
);
480 logError("C_Digest");
484 int DigestInit(Pkcs11Slot
& slot
, CK_MECHANISM_PTR mechanism
) {
485 d_err
= slot
.f()->C_DigestInit(slot
.Session(), mechanism
);
486 logError("C_DigestInit");
490 int DigestUpdate(Pkcs11Slot
& slot
, const std::string
& data
) {
491 d_err
= slot
.f()->C_DigestUpdate(slot
.Session(), (unsigned char*)data
.c_str(), data
.size());
492 logError("C_DigestUpdate");
496 int DigestKey(std::string
& result
) {
497 auto slot
= d_slot
->lock();
499 mech
.mechanism
= CKM_SHA_1
;
501 DigestInit(*slot
, &mech
);
503 if (d_key_type
== CKK_RSA
) {
504 DigestUpdate(*slot
, d_modulus
);
505 DigestUpdate(*slot
, d_exponent
);
506 } else if (d_key_type
== CKK_EC
|| d_key_type
== CKK_ECDSA
) {
507 DigestUpdate(*slot
, d_ec_point
);
510 DigestFinal(*slot
, result
);
515 int DigestFinal(Pkcs11Slot
& slot
, std::string
& result
) {
516 CK_BYTE buffer
[1024] = {0};
517 CK_ULONG buflen
= sizeof buffer
; // should be enough for most digests
519 d_err
= slot
.f()->C_DigestFinal(slot
.Session(), buffer
, &buflen
);
521 result
.assign((char*)buffer
, buflen
);
523 memset(buffer
,0,sizeof buffer
);
524 logError("C_DigestFinal");
528 int FindObjects2(Pkcs11Slot
& slot
, const std::vector
<P11KitAttribute
>& attributes
, std::vector
<CK_OBJECT_HANDLE
>& objects
, int maxobjects
) {
533 auto handles
= std::make_unique
<CK_OBJECT_HANDLE
[]>(maxobjects
);
534 auto attr
= std::make_unique
<CK_ATTRIBUTE
[]>(attributes
.size());
537 for(const P11KitAttribute
& attribute
: attributes
) {
538 attribute
.rattr(attr
.get()+k
);
543 d_err
= slot
.f()->C_FindObjectsInit(slot
.Session(), attr
.get(), k
);
546 logError("C_FindObjectsInit");
551 rv
= d_err
= slot
.f()->C_FindObjects(slot
.Session(), handles
.get(), maxobjects
, &count
);
555 for(k
=0;k
<count
;k
++) {
556 objects
.push_back((handles
.get())[k
]);
560 logError("C_FindObjects");
562 d_err
= slot
.f()->C_FindObjectsFinal(slot
.Session());
563 logError("C_FindObjectsFinal");
568 int GetAttributeValue2(Pkcs11Slot
& slot
, const CK_OBJECT_HANDLE
& object
, std::vector
<P11KitAttribute
>& attributes
)
571 auto attr
= std::make_unique
<CK_ATTRIBUTE
[]>(attributes
.size());
574 for(P11KitAttribute
&attribute
: attributes
) {
575 attribute
.wattr(attr
.get()+k
);
579 // round 1 - get attribute sizes
580 d_err
= slot
.f()->C_GetAttributeValue(slot
.Session(), object
, attr
.get(), attributes
.size());
581 logError("C_GetAttributeValue");
586 // then allocate memory
587 for(size_t idx
=0; idx
< attributes
.size(); idx
++) {
588 if (attributes
[idx
].valueType() == Attribute_String
) {
589 (attr
.get())[idx
].pValue
= attributes
[idx
].allocate((attr
.get())[idx
].ulValueLen
);
593 // round 2 - get actual values
594 d_err
= slot
.f()->C_GetAttributeValue(slot
.Session(), object
, attr
.get(), attributes
.size());
595 logError("C_GetAttributeValue");
597 // copy values to map and release allocated memory
598 for(size_t idx
=0; idx
< attributes
.size(); idx
++) {
599 if (attributes
[idx
].valueType() == Attribute_String
) {
600 attributes
[idx
].commit((attr
.get())[idx
].ulValueLen
);
607 const std::string
& Modulus() {
611 const std::string
& Exponent() {
615 const std::string
& ECPoint() {
619 const std::string
& ECParameters() {
620 return d_ecdsa_params
;
623 CK_KEY_TYPE
KeyType() {
631 static std::shared_ptr
<Pkcs11Token
> GetToken(const std::string
& module
, const string
& tokenId
, const std::string
& label
, const std::string
& pub_label
);
634 static std::map
<std::string
, std::shared_ptr
<LockGuarded
<Pkcs11Slot
> > > pkcs11_slots
;
635 static std::map
<std::string
, std::shared_ptr
<Pkcs11Token
> > pkcs11_tokens
;
637 CK_RV
Pkcs11Slot::HuntSlot(const string
& tokenId
, CK_SLOT_ID
&slotId
, _CK_SLOT_INFO
* info
, CK_FUNCTION_LIST
* functions
)
642 _CK_TOKEN_INFO tinfo
;
645 // this is required by certain tokens, otherwise C_GetSlotInfo will not return a token
646 err
= functions
->C_GetSlotList(CK_FALSE
, NULL_PTR
, &slots
);
648 g_log
<<Logger::Warning
<<"C_GetSlotList(CK_FALSE, NULL_PTR, &slots) = " << err
<< std::endl
;
652 // get the actual slot ids
653 std::vector
<CK_SLOT_ID
> slotIds(slots
);
654 err
= functions
->C_GetSlotList(CK_FALSE
, slotIds
.data(), &slots
);
656 g_log
<<Logger::Warning
<<"C_GetSlotList(CK_FALSE, slotIds, &slots) = " << err
<< std::endl
;
661 for(i
=0;i
<slots
;i
++) {
663 if (slotId
== static_cast<CK_SLOT_ID
>(-1))
665 if ((err
= functions
->C_GetSlotInfo(slotId
, info
))) {
666 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", info) = " << err
<< std::endl
;
669 if ((err
= functions
->C_GetTokenInfo(slotId
, &tinfo
))) {
670 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", &tinfo) = " << err
<< std::endl
;
673 std::string slotName
;
674 slotName
.assign(reinterpret_cast<char*>(tinfo
.label
), 32);
676 boost::trim(slotName
);
678 if (boost::iequals(slotName
, tokenId
)) {
683 // see if we can find it with slotId
685 slotId
= std::stoi(tokenId
);
686 if ((err
= functions
->C_GetSlotInfo(slotId
, info
))) {
687 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", info) = " << err
<< std::endl
;
690 g_log
<<Logger::Warning
<<"Specifying PKCS#11 token by SLOT ID is deprecated and should not be used"<<std::endl
;
693 return CKR_SLOT_ID_INVALID
;
695 return CKR_SLOT_ID_INVALID
;
698 std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> Pkcs11Slot::GetSlot(const std::string
& module
, const string
& tokenId
) {
699 // see if we can find module
700 std::string sidx
= module
;
702 sidx
.append(tokenId
);
703 std::map
<std::string
, std::shared_ptr
<LockGuarded
<Pkcs11Slot
> > >::iterator slotIter
;
705 CK_FUNCTION_LIST
* functions
;
707 // see if we have slot
708 if ((slotIter
= pkcs11_slots
.find(sidx
)) != pkcs11_slots
.end()) {
709 return slotIter
->second
;
712 #ifdef HAVE_P11KIT1_V2
713 functions
= p11_kit_module_for_name(p11_modules
, module
.c_str());
715 functions
= p11_kit_registered_name_to_module(module
.c_str());
717 if (functions
== nullptr) throw PDNSException("Cannot find PKCS#11 module " + module
);
718 functions
->C_Initialize(nullptr); // initialize the module in case it hasn't been done yet.
720 // try to locate a slot
724 if ((err
= Pkcs11Slot::HuntSlot(tokenId
, slotId
, &info
, functions
))) {
725 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
));
729 pkcs11_slots
[sidx
] = std::make_shared
<LockGuarded
<Pkcs11Slot
>>(Pkcs11Slot(functions
, slotId
));
731 return pkcs11_slots
[sidx
];
734 std::shared_ptr
<Pkcs11Token
> Pkcs11Token::GetToken(const std::string
& module
, const string
& tokenId
, const std::string
& label
, const std::string
& pub_label
) {
735 // see if we can find module
736 std::string tidx
= module
;
738 tidx
.append(tokenId
);
741 std::map
<std::string
, std::shared_ptr
<Pkcs11Token
> >::iterator tokenIter
;
742 if ((tokenIter
= pkcs11_tokens
.find(tidx
)) != pkcs11_tokens
.end()) return tokenIter
->second
;
744 std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> slot
= Pkcs11Slot::GetSlot(module
, tokenId
);
745 pkcs11_tokens
[tidx
] = std::make_shared
<Pkcs11Token
>(slot
, label
, pub_label
);
746 return pkcs11_tokens
[tidx
];
749 Pkcs11Token::Pkcs11Token(const std::shared_ptr
<LockGuarded
<Pkcs11Slot
>>& slot
, const std::string
& label
, const std::string
& pub_label
) :
753 d_pub_label(pub_label
),
758 if (this->d_slot
->lock()->LoggedIn()) LoadAttributes();
761 Pkcs11Token::~Pkcs11Token() {
764 bool PKCS11ModuleSlotLogin(const std::string
& module
, const string
& tokenId
, const std::string
& pin
)
766 std::shared_ptr
<LockGuarded
<Pkcs11Slot
>> slot
= Pkcs11Slot::GetSlot(module
, tokenId
);
767 if (slot
->lock()->LoggedIn()) return true; // no point failing
768 return slot
->lock()->Login(pin
);
771 PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(unsigned int algorithm
): DNSCryptoKeyEngine(algorithm
) {}
772 PKCS11DNSCryptoKeyEngine::~PKCS11DNSCryptoKeyEngine() {}
773 PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(const PKCS11DNSCryptoKeyEngine
& orig
) : DNSCryptoKeyEngine(orig
.d_algorithm
) {}
775 void PKCS11DNSCryptoKeyEngine::create(unsigned int bits
) {
776 std::vector
<P11KitAttribute
> pubAttr
;
777 std::vector
<P11KitAttribute
> privAttr
;
779 CK_OBJECT_HANDLE pubKey
, privKey
;
780 std::shared_ptr
<Pkcs11Token
> d_slot
;
781 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
782 if (d_slot
->LoggedIn() == false)
783 if (d_slot
->Login(d_pin
) == false)
784 throw PDNSException("Not logged in to token");
786 std::string
pubExp("\000\001\000\001", 4); // 65537
789 mech
.mechanism
= dnssec2cmech
.at(d_algorithm
);
790 } catch (std::out_of_range
& e
) {
791 throw PDNSException("pkcs11: unsupported algorithm "+std::to_string(d_algorithm
)+ " for key pair generation");
794 mech
.pParameter
= nullptr;
795 mech
.ulParameterLen
= 0;
797 if (mech
.mechanism
== CKM_RSA_PKCS_KEY_PAIR_GEN
) {
798 pubAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PUBLIC_KEY
));
799 pubAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_RSA
));
800 pubAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
801 pubAttr
.push_back(P11KitAttribute(CKA_ENCRYPT
, (char)CK_TRUE
));
802 pubAttr
.push_back(P11KitAttribute(CKA_VERIFY
, (char)CK_TRUE
));
803 pubAttr
.push_back(P11KitAttribute(CKA_WRAP
, (char)CK_TRUE
));
804 pubAttr
.push_back(P11KitAttribute(CKA_MODULUS_BITS
, (unsigned long)bits
));
805 pubAttr
.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT
, pubExp
));
806 pubAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_pub_label
));
808 privAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PRIVATE_KEY
));
809 privAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_RSA
));
810 privAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
811 privAttr
.push_back(P11KitAttribute(CKA_PRIVATE
, (char)CK_TRUE
));
812 // privAttr.push_back(P11KitAttribute(CKA_SUBJECT, "CN=keygen"));
813 privAttr
.push_back(P11KitAttribute(CKA_ID
, "\x01\x02\x03\x04")); // this is mandatory if you want to export anything
814 privAttr
.push_back(P11KitAttribute(CKA_SENSITIVE
, (char)CK_TRUE
));
815 privAttr
.push_back(P11KitAttribute(CKA_DECRYPT
, (char)CK_TRUE
));
816 privAttr
.push_back(P11KitAttribute(CKA_SIGN
, (char)CK_TRUE
));
817 privAttr
.push_back(P11KitAttribute(CKA_UNWRAP
, (char)CK_TRUE
));
818 privAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_label
));
819 } else if (mech
.mechanism
== CKM_ECDSA_KEY_PAIR_GEN
) {
820 pubAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PUBLIC_KEY
));
821 pubAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_ECDSA
));
822 pubAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
823 pubAttr
.push_back(P11KitAttribute(CKA_ENCRYPT
, (char)CK_TRUE
));
824 pubAttr
.push_back(P11KitAttribute(CKA_VERIFY
, (char)CK_TRUE
));
825 pubAttr
.push_back(P11KitAttribute(CKA_WRAP
, (char)CK_TRUE
));
826 pubAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_pub_label
));
827 if (d_algorithm
== 13) pubAttr
.push_back(P11KitAttribute(CKA_ECDSA_PARAMS
, ECDSA256_PARAMS
));
828 else if (d_algorithm
== 14) pubAttr
.push_back(P11KitAttribute(CKA_ECDSA_PARAMS
, ECDSA384_PARAMS
));
829 else throw PDNSException("pkcs11: unknown algorithm "+std::to_string(d_algorithm
)+" for ECDSA key pair generation");
831 privAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PRIVATE_KEY
));
832 privAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_ECDSA
));
833 privAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
834 privAttr
.push_back(P11KitAttribute(CKA_PRIVATE
, (char)CK_TRUE
));
835 // privAttr.push_back(P11KitAttribute(CKA_SUBJECT, "CN=keygen"));
836 privAttr
.push_back(P11KitAttribute(CKA_ID
, "\x01\x02\x03\x04")); // this is mandatory if you want to export anything
837 privAttr
.push_back(P11KitAttribute(CKA_SENSITIVE
, (char)CK_TRUE
));
838 privAttr
.push_back(P11KitAttribute(CKA_DECRYPT
, (char)CK_TRUE
));
839 privAttr
.push_back(P11KitAttribute(CKA_SIGN
, (char)CK_TRUE
));
840 privAttr
.push_back(P11KitAttribute(CKA_UNWRAP
, (char)CK_TRUE
));
841 privAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_label
));
843 throw PDNSException("pkcs11: don't know how make key for algorithm "+std::to_string(d_algorithm
));
847 if (d_slot
->GenerateKeyPair(&mech
, pubAttr
, privAttr
, &pubKey
, &privKey
)) {
848 throw PDNSException("Keypair generation failed");
852 std::string
PKCS11DNSCryptoKeyEngine::sign(const std::string
& msg
) const {
854 std::shared_ptr
<Pkcs11Token
> d_slot
;
855 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
856 if (d_slot
->LoggedIn() == false)
857 if (d_slot
->Login(d_pin
) == false)
858 throw PDNSException("Not logged in to token");
861 mech
.mechanism
= dnssec2smech
[d_algorithm
];
862 mech
.pParameter
= nullptr;
863 mech
.ulParameterLen
= 0;
865 if (mech
.mechanism
== CKM_ECDSA
) {
866 if (d_slot
->Sign(this->hash(msg
), result
, &mech
)) throw PDNSException("Could not sign data");
868 if (d_slot
->Sign(msg
, result
, &mech
)) throw PDNSException("Could not sign data");
873 std::string
PKCS11DNSCryptoKeyEngine::hash(const std::string
& msg
) const {
876 mech
.mechanism
= dnssec2hmech
[d_algorithm
];
877 mech
.pParameter
= nullptr;
878 mech
.ulParameterLen
= 0;
879 std::shared_ptr
<Pkcs11Token
> d_slot
;
880 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
881 if (d_slot
->LoggedIn() == false)
882 if (d_slot
->Login(d_pin
) == false)
883 throw PDNSException("Not logged in to token");
885 if (d_slot
->Digest(msg
, result
, &mech
)) {
886 g_log
<<Logger::Error
<<"Could not digest using PKCS#11 token - using software workaround"<<endl
;
887 // FINE! I'll do this myself, then, shall I?
888 switch(d_algorithm
) {
890 return pdns_sha1sum(msg
);
893 return pdns_sha256sum(msg
);
896 return pdns_sha512sum(msg
);
899 return pdns_sha256sum(msg
);
902 return pdns_sha384sum(msg
);
909 bool PKCS11DNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const {
910 std::shared_ptr
<Pkcs11Token
> d_slot
;
911 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
912 if (d_slot
->LoggedIn() == false)
913 if (d_slot
->Login(d_pin
) == false)
914 throw PDNSException("Not logged in to token");
917 mech
.mechanism
= dnssec2smech
[d_algorithm
];
918 mech
.pParameter
= nullptr;
919 mech
.ulParameterLen
= 0;
920 if (mech
.mechanism
== CKM_ECDSA
) {
921 return (d_slot
->Verify(this->hash(msg
), signature
, &mech
)==0);
923 return (d_slot
->Verify(msg
, signature
, &mech
) == 0);
927 std::string
PKCS11DNSCryptoKeyEngine::getPubKeyHash() const {
928 // find us a public key
929 std::shared_ptr
<Pkcs11Token
> d_slot
;
930 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
931 if (d_slot
->LoggedIn() == false)
932 if (d_slot
->Login(d_pin
) == false)
933 throw PDNSException("Not logged in to token");
936 if (d_slot
->DigestKey(result
) == 0) return result
;
937 throw PDNSException("Could not digest key (maybe it's missing?)");
940 std::string
PKCS11DNSCryptoKeyEngine::getPublicKeyString() const {
941 std::string
result("");
942 std::shared_ptr
<Pkcs11Token
> d_slot
;
943 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
944 if (d_slot
->LoggedIn() == false)
945 if (d_slot
->Login(d_pin
) == false)
946 throw PDNSException("Not logged in to token");
948 if (d_slot
->KeyType() == CKK_RSA
) {
949 if (d_slot
->Exponent().length() < 255) {
950 result
.assign(1, (char) (unsigned int) d_slot
->Exponent().length());
953 uint16_t len
=htons(d_slot
->Exponent().length());
954 result
.append((char*)&len
, 2);
956 result
.append(d_slot
->Exponent());
957 result
.append(d_slot
->Modulus());
959 result
.append(d_slot
->ECPoint());
964 int PKCS11DNSCryptoKeyEngine::getBits() const {
965 std::shared_ptr
<Pkcs11Token
> d_slot
;
966 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
967 if (d_slot
->LoggedIn() == false)
968 if (d_slot
->Login(d_pin
) == false)
969 throw PDNSException("Not logged in to token");
971 return d_slot
->Bits();
974 DNSCryptoKeyEngine::storvector_t
PKCS11DNSCryptoKeyEngine::convertToISCVector() const {
975 auto storvect
= storvector_t
{
976 {"Algorithm", std::to_string(d_algorithm
)},
977 {"Engine", d_module
},
981 {"PubLabel", d_pub_label
},
986 void PKCS11DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, stormap_t
& stormap
) {
987 pdns::checked_stoi_into(drc
.d_algorithm
, stormap
["algorithm"]);
988 d_module
= stormap
["engine"];
989 d_slot_id
= stormap
["slot"];
990 boost::trim(d_slot_id
);
991 d_pin
= stormap
["pin"];
992 d_label
= stormap
["label"];
993 if (stormap
.find("publabel") != stormap
.end())
994 d_pub_label
= stormap
["publabel"];
996 d_pub_label
= d_label
;
997 // validate parameters
999 std::shared_ptr
<Pkcs11Token
> d_slot
;
1000 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
1001 if (d_pin
!= "" && d_slot
->LoggedIn() == false)
1002 if (d_slot
->Login(d_pin
) == false)
1003 throw PDNSException("Could not log in to token (PIN wrong?)");
1006 std::unique_ptr
<DNSCryptoKeyEngine
> PKCS11DNSCryptoKeyEngine::maker(unsigned int algorithm
)
1008 return make_unique
<PKCS11DNSCryptoKeyEngine
>(algorithm
);
1011 // this is called during program startup
1013 static struct LoaderStruct
1017 #ifdef HAVE_P11KIT1_V2
1018 p11_modules
= p11_kit_modules_load_and_initialize(0);
1020 p11_kit_initialize_registered();
1024 #ifdef HAVE_P11KIT1_V2
1025 p11_kit_modules_release(p11_modules
);
1027 p11_kit_finalize_registered();