4 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
5 #include <boost/assign/list_of.hpp>
6 #include <boost/make_shared.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/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 // map for signing algorithms
46 static std::map
<unsigned int,CK_MECHANISM_TYPE
> dnssec2smech
= boost::assign::map_list_of
47 (5, CKM_SHA1_RSA_PKCS
)
48 (7, CKM_SHA1_RSA_PKCS
)
49 (8, CKM_SHA256_RSA_PKCS
)
50 (10, CKM_SHA512_RSA_PKCS
)
54 // map for hashing algorithms
55 static std::map
<unsigned int,CK_MECHANISM_TYPE
> dnssec2hmech
= boost::assign::map_list_of
63 typedef enum { Attribute_Byte
, Attribute_Long
, Attribute_String
} CkaValueType
;
66 class P11KitAttribute
{
68 CK_ATTRIBUTE_TYPE type
;
73 unsigned char *buffer
;
81 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, const std::string
& value
) {
87 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, char value
) {
93 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, unsigned char value
) {
99 P11KitAttribute(CK_ATTRIBUTE_TYPE type_
, unsigned long value
) {
105 CkaValueType
valueType() const {
109 const std::string
&str() const {
113 unsigned char byte() const {
117 unsigned long ulong() const {
121 void setString(const std::string
& value
) {
122 this->ckString
= value
;
123 this->ckType
= Attribute_String
;
126 void setByte(char value
) {
127 this->ckByte
= value
;
128 this->ckType
= Attribute_Byte
;
131 void setByte(unsigned char value
) {
132 this->ckByte
= value
;
133 this->ckType
= Attribute_Byte
;
136 void setLong(unsigned long value
) {
137 this->ckLong
= value
;
138 this->ckType
= Attribute_Long
;
141 // this bit is used for getting attribute from object
142 // we provide a pointer for GetAttributeValue to write to
143 CK_BYTE_PTR
allocate(CK_ULONG amount
) {
144 buffer
= new unsigned char[amount
];
149 // and here we copy the results back and delete buffer
150 void commit(CK_ULONG amount
) {
152 this->ckString
.assign((char*)buffer
, amount
);
159 // this is *writable* attribute (you write into it)
160 void wattr(CK_ATTRIBUTE_PTR attr
) {
163 case Attribute_Byte
: {
164 attr
->pValue
= (void*)&ckByte
;
165 attr
->ulValueLen
= 1;
168 case Attribute_Long
: {
169 attr
->pValue
= (void*)&ckLong
;
170 attr
->ulValueLen
= sizeof(CK_ULONG
);
173 case Attribute_String
: {
174 attr
->pValue
= buffer
;
175 attr
->ulValueLen
= buflen
;
180 // this is *readable* attribute (you read from it)
181 void rattr(CK_ATTRIBUTE_PTR attr
) const {
184 case Attribute_Byte
: {
185 attr
->pValue
= (void*)&ckByte
;
186 attr
->ulValueLen
= 1;
189 case Attribute_Long
: {
190 attr
->pValue
= (void*)&ckLong
;
191 attr
->ulValueLen
= sizeof(CK_ULONG
);
194 case Attribute_String
: {
195 attr
->pValue
= (void*)ckString
.c_str();
196 attr
->ulValueLen
= ckString
.size();
206 CK_FUNCTION_LIST
* d_functions
; // module functions
207 CK_SESSION_HANDLE d_session
;
212 void logError(const std::string
& operation
) const {
214 std::string msg
= boost::str( boost::format("PKCS#11 operation %s failed: %s (0x%X)") % operation
% p11_kit_strerror(d_err
) % d_err
);
215 g_log
<<Logger::Error
<< msg
<< endl
;
220 Pkcs11Slot(CK_FUNCTION_LIST
* functions
, const CK_SLOT_ID
& slot
) :
222 d_functions(functions
),
226 CK_TOKEN_INFO tokenInfo
;
227 pthread_mutex_init(&(this->d_m
), NULL
);
230 if ((d_err
= d_functions
->C_OpenSession(this->d_slot
, CKF_SERIAL_SESSION
|CKF_RW_SESSION
, 0, 0, &(this->d_session
)))) {
231 logError("C_OpenSession");
232 throw PDNSException("Could not open session");
234 // check if we need to login
235 if ((d_err
= d_functions
->C_GetTokenInfo(d_slot
, &tokenInfo
)) == 0) {
236 d_logged_in
= !((tokenInfo
.flags
& CKF_LOGIN_REQUIRED
) == CKF_LOGIN_REQUIRED
);
238 logError("C_GetTokenInfo");
239 throw PDNSException("Cannot get token info for slot " + std::to_string(slot
));
243 bool Login(const std::string
& pin
) {
244 if (d_logged_in
) return true;
246 unsigned char *uPin
= new unsigned char[pin
.size()];
247 memcpy(uPin
, pin
.c_str(), pin
.size());
248 d_err
= d_functions
->C_Login(this->d_session
, CKU_USER
, uPin
, pin
.size());
249 memset(uPin
, 0, pin
.size());
260 bool LoggedIn() const { return d_logged_in
; }
262 CK_SESSION_HANDLE
& Session() { return d_session
; }
264 CK_FUNCTION_LIST
* f() { return d_functions
; }
266 pthread_mutex_t
*m() { return &d_m
; }
268 static std::shared_ptr
<Pkcs11Slot
> GetSlot(const std::string
& module
, const string
& tokenId
);
269 static CK_RV
HuntSlot(const string
& tokenId
, CK_SLOT_ID
&slotId
, _CK_SLOT_INFO
* info
, CK_FUNCTION_LIST
* functions
);
274 std::shared_ptr
<Pkcs11Slot
> d_slot
;
276 CK_OBJECT_HANDLE d_public_key
;
277 CK_OBJECT_HANDLE d_private_key
;
278 CK_KEY_TYPE d_key_type
;
281 std::string d_exponent
;
282 std::string d_modulus
;
283 std::string d_ec_point
;
284 std::string d_ecdsa_params
;
287 std::string d_pub_label
;
292 void logError(const std::string
& operation
) const {
294 std::string msg
= boost::str( boost::format("PKCS#11 operation %s failed: %s (0x%X)") % operation
% p11_kit_strerror(d_err
) % d_err
);
295 g_log
<<Logger::Error
<< msg
<< endl
;
299 unsigned int ecparam2bits(const std::string
& obj
) const {
300 // if we can use some library to parse the EC parameters, better use it.
301 // otherwise fall back to using hardcoded primev256 and secp384r1
302 #ifdef HAVE_LIBCRYPTO_ECDSA
305 unsigned int bits
= 0;
306 const unsigned char *in
= reinterpret_cast<const unsigned char*>(obj
.c_str());
308 if ((key
= d2i_ECParameters(NULL
, &in
, obj
.size())) != NULL
&&
309 EC_GROUP_get_order(EC_KEY_get0_group(key
), order
, NULL
) == 1) {
310 bits
= BN_num_bits(order
);
318 throw PDNSException("Unsupported EC key");
322 if (d_ecdsa_params
== "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07") return 256;
323 else if (d_ecdsa_params
== "\x06\x05\x2b\x81\x04\x00\x22") return 384;
324 else throw PDNSException("Unsupported EC key");
329 Pkcs11Token(const std::shared_ptr
<Pkcs11Slot
>& slot
, const std::string
& label
, const std::string
& pub_label
);
332 bool Login(const std::string
& pin
) {
333 if (pin
.empty()) return false; // no empty pin.
334 if (d_slot
->Login(pin
) == true) {
342 if (d_loaded
== false && d_slot
->LoggedIn() == true) {
345 return d_slot
->LoggedIn();
348 void LoadAttributes() {
350 std::vector
<P11KitAttribute
> attr
;
351 std::vector
<CK_OBJECT_HANDLE
> key
;
352 attr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PRIVATE_KEY
));
353 // attr.push_back(P11KitAttribute(CKA_SIGN, (char)CK_TRUE));
354 attr
.push_back(P11KitAttribute(CKA_LABEL
, d_label
));
355 FindObjects2(attr
, key
, 1);
356 if (key
.size() == 0) {
357 g_log
<<Logger::Warning
<<"Cannot load PCKS#11 private key "<<d_label
<<std::endl
;;
360 d_private_key
= key
[0];
362 attr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PUBLIC_KEY
));
363 // attr.push_back(P11KitAttribute(CKA_VERIFY, (char)CK_TRUE));
364 attr
.push_back(P11KitAttribute(CKA_LABEL
, d_pub_label
));
365 FindObjects2(attr
, key
, 1);
366 if (key
.size() == 0) {
367 g_log
<<Logger::Warning
<<"Cannot load PCKS#11 public key "<<d_pub_label
<<std::endl
;
370 d_public_key
= key
[0];
373 attr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, 0UL));
375 if (GetAttributeValue2(d_public_key
, attr
)==0) {
376 d_key_type
= attr
[0].ulong();
377 if (d_key_type
== CKK_RSA
) {
379 attr
.push_back(P11KitAttribute(CKA_MODULUS
, ""));
380 attr
.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT
, ""));
381 attr
.push_back(P11KitAttribute(CKA_MODULUS_BITS
, 0UL));
383 if (!GetAttributeValue2(d_public_key
, attr
)) {
384 d_modulus
= attr
[0].str();
385 d_exponent
= attr
[1].str();
386 d_bits
= attr
[2].ulong();
388 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label
);
390 } else if (d_key_type
== CKK_EC
|| d_key_type
== CKK_ECDSA
) {
392 attr
.push_back(P11KitAttribute(CKA_ECDSA_PARAMS
, ""));
393 attr
.push_back(P11KitAttribute(CKA_EC_POINT
, ""));
394 if (!GetAttributeValue2(d_public_key
, attr
)) {
395 d_ecdsa_params
= attr
[0].str();
396 d_bits
= ecparam2bits(d_ecdsa_params
);
397 if (attr
[1].str().length() != (d_bits
*2/8 + 3)) throw PDNSException("EC Point data invalid");
398 d_ec_point
= attr
[1].str().substr(3);
400 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label
);
403 throw PDNSException("Cannot determine type for PCKS#11 public key " + d_pub_label
);
406 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label
);
412 int GenerateKeyPair(CK_MECHANISM_PTR mechanism
, std::vector
<P11KitAttribute
>& pubAttributes
, std::vector
<P11KitAttribute
>& privAttributes
, CK_OBJECT_HANDLE_PTR pubKey
, CK_OBJECT_HANDLE_PTR privKey
) {
417 CK_ATTRIBUTE_PTR pubAttr
, privAttr
;
418 pubAttr
= new CK_ATTRIBUTE
[pubAttributes
.size()];
419 privAttr
= new CK_ATTRIBUTE
[privAttributes
.size()];
422 for(P11KitAttribute
& attribute
: pubAttributes
) {
423 attribute
.rattr(pubAttr
+k
);
428 for(P11KitAttribute
& attribute
: privAttributes
) {
429 attribute
.rattr(privAttr
+k
);
433 d_err
= this->d_slot
->f()->C_GenerateKeyPair(d_slot
->Session(), mechanism
, pubAttr
, pubAttributes
.size(), privAttr
, privAttributes
.size(), pubKey
, privKey
);
434 logError("C_GenerateKeyPair");
439 if (d_err
== 0) LoadAttributes();
444 int Sign(const std::string
& data
, std::string
& result
, CK_MECHANISM_PTR mechanism
) {
447 CK_BYTE buffer
[1024];
448 CK_ULONG buflen
= sizeof buffer
; // should be enough for most signatures.
451 if ((d_err
= this->d_slot
->f()->C_SignInit(d_slot
->Session(), mechanism
, d_private_key
))) { logError("C_SignInit"); return d_err
; }
452 d_err
= this->d_slot
->f()->C_Sign(d_slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), buffer
, &buflen
);
455 result
.assign((char*)buffer
, buflen
);
458 memset(buffer
,0,sizeof buffer
);
463 int Verify(const std::string
& data
, const std::string
& signature
, CK_MECHANISM_PTR mechanism
) {
466 if ((d_err
= this->d_slot
->f()->C_VerifyInit(d_slot
->Session(), mechanism
, d_public_key
))) { logError("C_VerifyInit"); return d_err
; }
467 d_err
= this->d_slot
->f()->C_Verify(d_slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), (unsigned char*)signature
.c_str(), signature
.size());
468 logError("C_Verify");
472 int Digest(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 digests
477 if ((d_err
= this->d_slot
->f()->C_DigestInit(d_slot
->Session(), mechanism
))) { logError("C_DigestInit"); return d_err
; }
478 d_err
= this->d_slot
->f()->C_Digest(d_slot
->Session(), (unsigned char*)data
.c_str(), data
.size(), buffer
, &buflen
);
480 result
.assign((char*)buffer
, buflen
);
482 memset(buffer
,0,sizeof buffer
);
483 logError("C_Digest");
487 int DigestInit(CK_MECHANISM_PTR mechanism
) {
488 d_err
= d_slot
->f()->C_DigestInit(d_slot
->Session(), mechanism
);
489 logError("C_DigestInit");
493 int DigestUpdate(const std::string
& data
) {
494 d_err
= d_slot
->f()->C_DigestUpdate(d_slot
->Session(), (unsigned char*)data
.c_str(), data
.size());
495 logError("C_DigestUpdate");
499 int DigestKey(std::string
& result
) {
502 mech
.mechanism
= CKM_SHA_1
;
506 if (d_key_type
== CKK_RSA
) {
507 DigestUpdate(d_modulus
);
508 DigestUpdate(d_exponent
);
509 } else if (d_key_type
== CKK_EC
|| d_key_type
== CKK_ECDSA
) {
510 DigestUpdate(d_ec_point
);
518 int DigestFinal(std::string
& result
) {
519 CK_BYTE buffer
[1024] = {0};
520 CK_ULONG buflen
= sizeof buffer
; // should be enough for most digests
521 d_err
= d_slot
->f()->C_DigestFinal(d_slot
->Session(), buffer
, &buflen
);
523 result
.assign((char*)buffer
, buflen
);
525 memset(buffer
,0,sizeof buffer
);
526 logError("C_DigestFinal");
530 int FindObjects(const std::vector
<P11KitAttribute
>& attributes
, std::vector
<CK_OBJECT_HANDLE
>& objects
, int maxobjects
) {
532 return FindObjects2(attributes
, objects
, maxobjects
);
535 int FindObjects2(const std::vector
<P11KitAttribute
>& attributes
, std::vector
<CK_OBJECT_HANDLE
>& objects
, int maxobjects
) {
540 CK_ATTRIBUTE_PTR attr
;
541 CK_OBJECT_HANDLE_PTR handles
= new CK_OBJECT_HANDLE
[maxobjects
];
542 attr
= new CK_ATTRIBUTE
[attributes
.size()];
545 for(const P11KitAttribute
& attribute
: attributes
) {
546 attribute
.rattr(attr
+k
);
551 d_err
= this->d_slot
->f()->C_FindObjectsInit(d_slot
->Session(), attr
, k
);
556 logError("C_FindObjectsInit");
561 rv
= d_err
= this->d_slot
->f()->C_FindObjects(d_slot
->Session(), handles
, maxobjects
, &count
);
565 for(k
=0;k
<count
;k
++) {
566 objects
.push_back(handles
[k
]);
570 logError("C_FindObjects");
575 d_err
= this->d_slot
->f()->C_FindObjectsFinal(d_slot
->Session());
576 logError("C_FindObjectsFinal");
581 int GetAttributeValue(const CK_OBJECT_HANDLE
& object
, std::vector
<P11KitAttribute
>& attributes
)
584 return GetAttributeValue2(object
, attributes
);
587 int GetAttributeValue2(const CK_OBJECT_HANDLE
& object
, std::vector
<P11KitAttribute
>& attributes
)
590 CK_ATTRIBUTE_PTR attr
;
591 attr
= new CK_ATTRIBUTE
[attributes
.size()];
594 for(P11KitAttribute
&attribute
: attributes
) {
595 attribute
.wattr(attr
+k
);
599 // round 1 - get attribute sizes
600 d_err
= d_slot
->f()->C_GetAttributeValue(d_slot
->Session(), object
, attr
, attributes
.size());
601 logError("C_GetAttributeValue");
607 // then allocate memory
608 for(size_t idx
=0; idx
< attributes
.size(); idx
++) {
609 if (attributes
[idx
].valueType() == Attribute_String
) {
610 attr
[idx
].pValue
= attributes
[idx
].allocate(attr
[idx
].ulValueLen
);
614 // round 2 - get actual values
615 d_err
= d_slot
->f()->C_GetAttributeValue(d_slot
->Session(), object
, attr
, attributes
.size());
616 logError("C_GetAttributeValue");
618 // copy values to map and release allocated memory
619 for(size_t idx
=0; idx
< attributes
.size(); idx
++) {
620 if (attributes
[idx
].valueType() == Attribute_String
) {
621 attributes
[idx
].commit(attr
[idx
].ulValueLen
);
630 const std::string
& Modulus() {
634 const std::string
& Exponent() {
638 const std::string
& ECPoint() {
642 const std::string
& ECParameters() {
643 return d_ecdsa_params
;
646 CK_KEY_TYPE
KeyType() {
654 static std::shared_ptr
<Pkcs11Token
> GetToken(const std::string
& module
, const string
& tokenId
, const std::string
& label
, const std::string
& pub_label
);
657 static std::map
<std::string
, std::shared_ptr
<Pkcs11Slot
> > pkcs11_slots
;
658 static std::map
<std::string
, std::shared_ptr
<Pkcs11Token
> > pkcs11_tokens
;
660 CK_RV
Pkcs11Slot::HuntSlot(const string
& tokenId
, CK_SLOT_ID
&slotId
, _CK_SLOT_INFO
* info
, CK_FUNCTION_LIST
* functions
)
665 _CK_TOKEN_INFO tinfo
;
668 // this is required by certain tokens, otherwise C_GetSlotInfo will not return a token
669 err
= functions
->C_GetSlotList(CK_FALSE
, NULL_PTR
, &slots
);
671 g_log
<<Logger::Warning
<<"C_GetSlotList(CK_FALSE, NULL_PTR, &slots) = " << err
<< std::endl
;
675 // get the actual slot ids
676 std::vector
<CK_SLOT_ID
> slotIds(slots
);
677 err
= functions
->C_GetSlotList(CK_FALSE
, slotIds
.data(), &slots
);
679 g_log
<<Logger::Warning
<<"C_GetSlotList(CK_FALSE, slotIds, &slots) = " << err
<< std::endl
;
684 for(i
=0;i
<slots
;i
++) {
686 if (slotId
== static_cast<CK_SLOT_ID
>(-1))
688 if ((err
= functions
->C_GetSlotInfo(slotId
, info
))) {
689 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", info) = " << err
<< std::endl
;
692 if ((err
= functions
->C_GetTokenInfo(slotId
, &tinfo
))) {
693 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", &tinfo) = " << err
<< std::endl
;
696 std::string slotName
;
697 slotName
.assign(reinterpret_cast<char*>(tinfo
.label
), 32);
699 boost::trim(slotName
);
701 if (boost::iequals(slotName
, tokenId
)) {
706 // see if we can find it with slotId
708 slotId
= std::stoi(tokenId
);
709 if ((err
= functions
->C_GetSlotInfo(slotId
, info
))) {
710 g_log
<<Logger::Warning
<<"C_GetSlotList("<<slotId
<<", info) = " << err
<< std::endl
;
713 g_log
<<Logger::Warning
<<"Specifying PKCS#11 token by SLOT ID is deprecated and should not be used"<<std::endl
;
716 return CKR_SLOT_ID_INVALID
;
718 return CKR_SLOT_ID_INVALID
;
721 std::shared_ptr
<Pkcs11Slot
> Pkcs11Slot::GetSlot(const std::string
& module
, const string
& tokenId
) {
722 // see if we can find module
723 std::string sidx
= module
;
725 sidx
.append(tokenId
);
726 std::map
<std::string
, std::shared_ptr
<Pkcs11Slot
> >::iterator slotIter
;
728 CK_FUNCTION_LIST
* functions
;
730 // see if we have slot
731 if ((slotIter
= pkcs11_slots
.find(sidx
)) != pkcs11_slots
.end()) {
732 return slotIter
->second
;
735 #ifdef HAVE_P11KIT1_V2
736 functions
= p11_kit_module_for_name(p11_modules
, module
.c_str());
738 functions
= p11_kit_registered_name_to_module(module
.c_str());
740 if (functions
== NULL
) throw PDNSException("Cannot find PKCS#11 module " + module
);
741 functions
->C_Initialize(NULL
); // initialize the module in case it hasn't been done yet.
743 // try to locate a slot
747 if ((err
= Pkcs11Slot::HuntSlot(tokenId
, slotId
, &info
, functions
))) {
748 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
));
752 pkcs11_slots
[sidx
] = std::make_shared
<Pkcs11Slot
>(functions
, slotId
);
754 return pkcs11_slots
[sidx
];
757 std::shared_ptr
<Pkcs11Token
> Pkcs11Token::GetToken(const std::string
& module
, const string
& tokenId
, const std::string
& label
, const std::string
& pub_label
) {
758 // see if we can find module
759 std::string tidx
= module
;
761 tidx
.append(tokenId
);
764 std::map
<std::string
, std::shared_ptr
<Pkcs11Token
> >::iterator tokenIter
;
765 if ((tokenIter
= pkcs11_tokens
.find(tidx
)) != pkcs11_tokens
.end()) return tokenIter
->second
;
767 std::shared_ptr
<Pkcs11Slot
> slot
= Pkcs11Slot::GetSlot(module
, tokenId
);
768 pkcs11_tokens
[tidx
] = std::make_shared
<Pkcs11Token
>(slot
, label
, pub_label
);
769 return pkcs11_tokens
[tidx
];
772 Pkcs11Token::Pkcs11Token(const std::shared_ptr
<Pkcs11Slot
>& slot
, const std::string
& label
, const std::string
& pub_label
) :
776 d_pub_label(pub_label
),
781 if (this->d_slot
->LoggedIn()) LoadAttributes();
784 Pkcs11Token::~Pkcs11Token() {
787 bool PKCS11ModuleSlotLogin(const std::string
& module
, const string
& tokenId
, const std::string
& pin
)
789 std::shared_ptr
<Pkcs11Slot
> slot
;
790 slot
= Pkcs11Slot::GetSlot(module
, tokenId
);
791 if (slot
->LoggedIn()) return true; // no point failing
792 return slot
->Login(pin
);
795 PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(unsigned int algorithm
): DNSCryptoKeyEngine(algorithm
) {}
796 PKCS11DNSCryptoKeyEngine::~PKCS11DNSCryptoKeyEngine() {}
797 PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(const PKCS11DNSCryptoKeyEngine
& orig
) : DNSCryptoKeyEngine(orig
.d_algorithm
) {}
799 void PKCS11DNSCryptoKeyEngine::create(unsigned int bits
) {
800 std::vector
<P11KitAttribute
> pubAttr
;
801 std::vector
<P11KitAttribute
> privAttr
;
803 CK_OBJECT_HANDLE pubKey
, privKey
;
805 std::shared_ptr
<Pkcs11Token
> d_slot
;
806 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
807 if (d_slot
->LoggedIn() == false)
808 if (d_slot
->Login(d_pin
) == false)
809 throw PDNSException("Not logged in to token");
811 std::string
pubExp("\000\001\000\001", 4); // 65537
813 pubAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PUBLIC_KEY
));
814 pubAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_RSA
));
815 pubAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
816 pubAttr
.push_back(P11KitAttribute(CKA_ENCRYPT
, (char)CK_TRUE
));
817 pubAttr
.push_back(P11KitAttribute(CKA_VERIFY
, (char)CK_TRUE
));
818 pubAttr
.push_back(P11KitAttribute(CKA_WRAP
, (char)CK_TRUE
));
819 pubAttr
.push_back(P11KitAttribute(CKA_MODULUS_BITS
, (unsigned long)bits
));
820 pubAttr
.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT
, pubExp
));
821 pubAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_pub_label
));
823 privAttr
.push_back(P11KitAttribute(CKA_CLASS
, (unsigned long)CKO_PRIVATE_KEY
));
824 privAttr
.push_back(P11KitAttribute(CKA_KEY_TYPE
, (unsigned long)CKK_RSA
));
825 privAttr
.push_back(P11KitAttribute(CKA_TOKEN
, (char)CK_TRUE
));
826 privAttr
.push_back(P11KitAttribute(CKA_PRIVATE
, (char)CK_TRUE
));
827 // privAttr.push_back(P11KitAttribute(CKA_SUBJECT, "CN=keygen"));
828 privAttr
.push_back(P11KitAttribute(CKA_ID
, "\x01\x02\x03\x04")); // this is mandatory if you want to export anything
829 privAttr
.push_back(P11KitAttribute(CKA_SENSITIVE
, (char)CK_TRUE
));
830 privAttr
.push_back(P11KitAttribute(CKA_DECRYPT
, (char)CK_TRUE
));
831 privAttr
.push_back(P11KitAttribute(CKA_SIGN
, (char)CK_TRUE
));
832 privAttr
.push_back(P11KitAttribute(CKA_UNWRAP
, (char)CK_TRUE
));
833 privAttr
.push_back(P11KitAttribute(CKA_LABEL
, d_label
));
835 mech
.mechanism
= CKM_RSA_PKCS_KEY_PAIR_GEN
;
836 mech
.pParameter
= NULL
;
837 mech
.ulParameterLen
= 0;
839 if ((rv
= d_slot
->GenerateKeyPair(&mech
, pubAttr
, privAttr
, &pubKey
, &privKey
))) {
840 throw PDNSException("Keypair generation failed");
844 std::string
PKCS11DNSCryptoKeyEngine::sign(const std::string
& msg
) const {
846 std::shared_ptr
<Pkcs11Token
> d_slot
;
847 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
848 if (d_slot
->LoggedIn() == false)
849 if (d_slot
->Login(d_pin
) == false)
850 throw PDNSException("Not logged in to token");
853 mech
.mechanism
= dnssec2smech
[d_algorithm
];
854 mech
.pParameter
= NULL
;
855 mech
.ulParameterLen
= 0;
857 if (mech
.mechanism
== CKM_ECDSA
) {
858 if (d_slot
->Sign(this->hash(msg
), result
, &mech
)) throw PDNSException("Could not sign data");
860 if (d_slot
->Sign(msg
, result
, &mech
)) throw PDNSException("Could not sign data");
865 std::string
PKCS11DNSCryptoKeyEngine::hash(const std::string
& msg
) const {
868 mech
.mechanism
= dnssec2hmech
[d_algorithm
];
869 mech
.pParameter
= NULL
;
870 mech
.ulParameterLen
= 0;
871 std::shared_ptr
<Pkcs11Token
> d_slot
;
872 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
873 if (d_slot
->LoggedIn() == false)
874 if (d_slot
->Login(d_pin
) == false)
875 throw PDNSException("Not logged in to token");
877 if (d_slot
->Digest(msg
, result
, &mech
)) {
878 g_log
<<Logger::Error
<<"Could not digest using PKCS#11 token - using software workaround"<<endl
;
879 // FINE! I'll do this myself, then, shall I?
880 switch(d_algorithm
) {
882 return pdns_sha1sum(msg
);
885 return pdns_sha256sum(msg
);
888 return pdns_sha512sum(msg
);
891 return pdns_sha256sum(msg
);
894 return pdns_sha384sum(msg
);
901 bool PKCS11DNSCryptoKeyEngine::verify(const std::string
& msg
, const std::string
& signature
) const {
902 std::shared_ptr
<Pkcs11Token
> d_slot
;
903 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
904 if (d_slot
->LoggedIn() == false)
905 if (d_slot
->Login(d_pin
) == false)
906 throw PDNSException("Not logged in to token");
909 mech
.mechanism
= dnssec2smech
[d_algorithm
];
910 mech
.pParameter
= NULL
;
911 mech
.ulParameterLen
= 0;
912 if (mech
.mechanism
== CKM_ECDSA
) {
913 return (d_slot
->Verify(this->hash(msg
), signature
, &mech
)==0);
915 return (d_slot
->Verify(msg
, signature
, &mech
) == 0);
919 std::string
PKCS11DNSCryptoKeyEngine::getPubKeyHash() const {
920 // find us a public key
921 std::shared_ptr
<Pkcs11Token
> d_slot
;
922 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
923 if (d_slot
->LoggedIn() == false)
924 if (d_slot
->Login(d_pin
) == false)
925 throw PDNSException("Not logged in to token");
928 if (d_slot
->DigestKey(result
) == 0) return result
;
929 throw PDNSException("Could not digest key (maybe it's missing?)");
932 std::string
PKCS11DNSCryptoKeyEngine::getPublicKeyString() const {
933 std::string
result("");
934 std::shared_ptr
<Pkcs11Token
> d_slot
;
935 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
936 if (d_slot
->LoggedIn() == false)
937 if (d_slot
->Login(d_pin
) == false)
938 throw PDNSException("Not logged in to token");
940 if (d_slot
->KeyType() == CKK_RSA
) {
941 if (d_slot
->Exponent().length() < 255) {
942 result
.assign(1, (char) (unsigned int) d_slot
->Exponent().length());
945 uint16_t len
=htons(d_slot
->Exponent().length());
946 result
.append((char*)&len
, 2);
948 result
.append(d_slot
->Exponent());
949 result
.append(d_slot
->Modulus());
951 result
.append(d_slot
->ECPoint());
956 int PKCS11DNSCryptoKeyEngine::getBits() const {
957 std::shared_ptr
<Pkcs11Token
> d_slot
;
958 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
959 if (d_slot
->LoggedIn() == false)
960 if (d_slot
->Login(d_pin
) == false)
961 throw PDNSException("Not logged in to token");
963 return d_slot
->Bits();
966 DNSCryptoKeyEngine::storvector_t
PKCS11DNSCryptoKeyEngine::convertToISCVector() const {
967 storvector_t storvect
;
968 typedef std::vector
<std::pair
<std::string
, std::string
> > outputs_t
;
971 boost::assign::push_back(storvect
)
972 (make_pair("Algorithm", std::to_string(d_algorithm
)))
973 (make_pair("Engine", d_module
))
974 (make_pair("Slot", d_slot_id
))
975 (make_pair("PIN", d_pin
))
976 (make_pair("Label", d_label
))
977 (make_pair("PubLabel", d_pub_label
));
981 void PKCS11DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent
& drc
, stormap_t
& stormap
) {
982 drc
.d_algorithm
= pdns_stou(stormap
["algorithm"]);
983 d_module
= stormap
["engine"];
984 d_slot_id
= stormap
["slot"];
985 boost::trim(d_slot_id
);
986 d_pin
= stormap
["pin"];
987 d_label
= stormap
["label"];
988 if (stormap
.find("publabel") != stormap
.end())
989 d_pub_label
= stormap
["publabel"];
991 d_pub_label
= d_label
;
992 // validate parameters
994 std::shared_ptr
<Pkcs11Token
> d_slot
;
995 d_slot
= Pkcs11Token::GetToken(d_module
, d_slot_id
, d_label
, d_pub_label
);
996 if (d_pin
!= "" && d_slot
->LoggedIn() == false)
997 if (d_slot
->Login(d_pin
) == false)
998 throw PDNSException("Could not log in to token (PIN wrong?)");
1001 std::shared_ptr
<DNSCryptoKeyEngine
> PKCS11DNSCryptoKeyEngine::maker(unsigned int algorithm
)
1003 return std::make_shared
<PKCS11DNSCryptoKeyEngine
>(algorithm
);
1006 // this is called during program startup
1008 static struct LoaderStruct
1012 #ifdef HAVE_P11KIT1_V2
1013 p11_modules
= p11_kit_modules_load_and_initialize(0);
1015 p11_kit_initialize_registered();
1019 #ifdef HAVE_P11KIT1_V2
1020 p11_kit_modules_release(p11_modules
);
1022 p11_kit_finalize_registered();