]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/pkcs11signers.cc
updated KSK and ZSK Rollover procedures, small fixes in Algorithm Rollover procedure
[thirdparty/pdns.git] / pdns / pkcs11signers.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
5 #include <boost/assign/list_of.hpp>
6
7 #include <boost/format.hpp>
8 #include <p11-kit/p11-kit.h>
9
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"
15
16 #ifdef HAVE_LIBCRYPTO_ECDSA
17 #include <openssl/bn.h>
18 #include <openssl/ec.h>
19 #endif
20
21 #include "pkcs11signers.hh"
22 /* TODO
23
24 - list possible tokens and supported modes
25 - Engine: <name>, Slot: <slot>, PIN: <pin>
26 - ECDSA support (how to test?)
27
28 NB! If you do use this, here is a simple way to get softhsm working
29
30 create /etc/pkcs11/modules/softhsm.module
31
32 put
33
34 module: /usr/lib/softhsm/libsofthsm.so
35 managed: yes
36
37 in it. you need to use softhsm tools to manage this all.
38
39 */
40
41 #ifdef HAVE_P11KIT1_V2
42 static CK_FUNCTION_LIST** p11_modules;
43 #endif
44
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"
47
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)
54 (13, CKM_ECDSA)
55 (14, CKM_ECDSA);
56
57 // map for hashing algorithms
58 static std::map<unsigned int,CK_MECHANISM_TYPE> dnssec2hmech = boost::assign::map_list_of
59 (5, CKM_SHA_1)
60 (7, CKM_SHA_1)
61 (8, CKM_SHA256)
62 (10, CKM_SHA512)
63 (13, CKM_SHA256)
64 (14, CKM_SHA384);
65
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);
73
74 typedef enum { Attribute_Byte, Attribute_Long, Attribute_String } CkaValueType;
75
76 // Attribute handling
77 class P11KitAttribute {
78 private:
79 CK_ATTRIBUTE_TYPE type;
80 CK_BYTE ckByte;
81 CK_ULONG ckLong;
82 std::string ckString;
83 CkaValueType ckType;
84 std::unique_ptr<unsigned char[]> buffer;
85 CK_ULONG buflen;
86 protected:
87 void Init() {
88 buflen = 0;
89 };
90 public:
91 P11KitAttribute(CK_ATTRIBUTE_TYPE type_, const std::string& value) {
92 Init();
93 this->type = type_;
94 setString(value);
95 }
96
97 P11KitAttribute(CK_ATTRIBUTE_TYPE type_, char value) {
98 Init();
99 this->type = type_;
100 setByte(value);
101 }
102
103 P11KitAttribute(CK_ATTRIBUTE_TYPE type_, unsigned char value) {
104 Init();
105 this->type = type_;
106 setByte(value);
107 }
108
109 P11KitAttribute(CK_ATTRIBUTE_TYPE type_, unsigned long value) {
110 Init();
111 this->type = type_;
112 setLong(value);
113 }
114
115 CkaValueType valueType() const {
116 return ckType;
117 }
118
119 const std::string &str() const {
120 return ckString;
121 };
122
123 unsigned char byte() const {
124 return ckByte;
125 }
126
127 unsigned long ulong() const {
128 return ckLong;
129 }
130
131 void setString(const std::string& value) {
132 this->ckString = value;
133 this->ckType = Attribute_String;
134 }
135
136 void setByte(char value) {
137 this->ckByte = value;
138 this->ckType = Attribute_Byte;
139 }
140
141 void setByte(unsigned char value) {
142 this->ckByte = value;
143 this->ckType = Attribute_Byte;
144 }
145
146 void setLong(unsigned long value) {
147 this->ckLong = value;
148 this->ckType = Attribute_Long;
149 }
150
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);
155 buflen = amount;
156 return buffer.get();
157 }
158
159 // and here we copy the results back and delete buffer
160 void commit(CK_ULONG amount) {
161 if (buffer) {
162 this->ckString.assign((char*)buffer.get(), amount);
163 }
164 buffer.reset();
165 buflen = 0;
166 }
167
168 // this is *writable* attribute (you write into it)
169 void wattr(CK_ATTRIBUTE_PTR attr) {
170 attr->type = type;
171 switch(ckType) {
172 case Attribute_Byte: {
173 attr->pValue = (void*)&ckByte;
174 attr->ulValueLen = 1;
175 break;
176 }
177 case Attribute_Long: {
178 attr->pValue = (void*)&ckLong;
179 attr->ulValueLen = sizeof(CK_ULONG);
180 break;
181 }
182 case Attribute_String: {
183 attr->pValue = buffer.get();
184 attr->ulValueLen = buflen;
185 }
186 };
187 };
188
189 // this is *readable* attribute (you read from it)
190 void rattr(CK_ATTRIBUTE_PTR attr) const {
191 attr->type = type;
192 switch(ckType) {
193 case Attribute_Byte: {
194 attr->pValue = (void*)&ckByte;
195 attr->ulValueLen = 1;
196 break;
197 }
198 case Attribute_Long: {
199 attr->pValue = (void*)&ckLong;
200 attr->ulValueLen = sizeof(CK_ULONG);
201 break;
202 }
203 case Attribute_String: {
204 attr->pValue = (void*)ckString.c_str();
205 attr->ulValueLen = ckString.size();
206 }
207 };
208 };
209 };
210
211
212 class Pkcs11Slot {
213 private:
214 bool d_logged_in;
215 CK_FUNCTION_LIST* d_functions; // module functions
216 CK_SESSION_HANDLE d_session;
217 CK_SLOT_ID d_slot;
218 CK_RV d_err;
219
220 void logError(const std::string& operation) const {
221 if (d_err) {
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;
224 }
225 }
226
227 public:
228 Pkcs11Slot(CK_FUNCTION_LIST* functions, const CK_SLOT_ID& slot) :
229 d_logged_in(false),
230 d_functions(functions),
231 d_slot(slot),
232 d_err(0)
233 {
234 CK_TOKEN_INFO tokenInfo;
235
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");
239 }
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);
243 } else {
244 logError("C_GetTokenInfo");
245 throw PDNSException("Cannot get token info for slot " + std::to_string(slot));
246 }
247 }
248
249 bool Login(const std::string& pin) {
250 if (d_logged_in) return true;
251
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());
256 logError("C_Login");
257
258 if (d_err == 0) {
259 d_logged_in = true;
260 }
261
262 return d_logged_in;
263 }
264
265 bool LoggedIn() const { return d_logged_in; }
266
267 CK_SESSION_HANDLE& Session() { return d_session; }
268
269 CK_FUNCTION_LIST* f() { return d_functions; }
270
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);
273 };
274
275 class Pkcs11Token {
276 private:
277 std::shared_ptr<LockGuarded<Pkcs11Slot>> d_slot;
278
279 CK_OBJECT_HANDLE d_public_key;
280 CK_OBJECT_HANDLE d_private_key;
281 CK_KEY_TYPE d_key_type;
282
283 CK_ULONG d_bits;
284 std::string d_exponent;
285 std::string d_modulus;
286 std::string d_ec_point;
287 std::string d_ecdsa_params;
288
289 std::string d_label;
290 std::string d_pub_label;
291
292 bool d_loaded;
293 CK_RV d_err;
294
295 void logError(const std::string& operation) const {
296 if (d_err) {
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;
299 }
300 }
301
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);
312 tempKey = nullptr;
313 if (EC_GROUP_get_order(EC_KEY_get0_group(key.get()), order.get(), nullptr) == 1) {
314 bits = BN_num_bits(order.get());
315 }
316 }
317
318 if (bits == 0)
319 throw PDNSException("Unsupported EC key");
320
321 return bits;
322 #else
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");
326 #endif
327 }
328
329 public:
330 Pkcs11Token(const std::shared_ptr<LockGuarded<Pkcs11Slot>>& slot, const std::string& label, const std::string& pub_label);
331 ~Pkcs11Token();
332
333 bool Login(const std::string& pin) {
334 if (pin.empty()) return false; // no empty pin.
335 if (d_slot->lock()->Login(pin) == true) {
336 LoadAttributes();
337 }
338
339 return LoggedIn();
340 }
341
342 bool LoggedIn() {
343 if (d_loaded == false && d_slot->lock()->LoggedIn() == true) {
344 LoadAttributes();
345 }
346 return d_slot->lock()->LoggedIn();
347 }
348
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;;
359 return;
360 }
361 d_private_key = key[0];
362 attr.clear();
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;
369 return;
370 }
371 d_public_key = key[0];
372
373 attr.clear();
374 attr.push_back(P11KitAttribute(CKA_KEY_TYPE, 0UL));
375
376 if (GetAttributeValue2(*slot, d_public_key, attr)==0) {
377 d_key_type = attr[0].ulong();
378 if (d_key_type == CKK_RSA) {
379 attr.clear();
380 attr.push_back(P11KitAttribute(CKA_MODULUS, ""));
381 attr.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT, ""));
382 attr.push_back(P11KitAttribute(CKA_MODULUS_BITS, 0UL));
383
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();
388 } else {
389 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label);
390 }
391 } else if (d_key_type == CKK_EC || d_key_type == CKK_ECDSA) {
392 attr.clear();
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);
400 } else {
401 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label);
402 }
403 } else {
404 throw PDNSException("Cannot determine type for PCKS#11 public key " + d_pub_label);
405 }
406 } else {
407 throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_pub_label);
408 }
409
410 d_loaded = true;
411 }
412
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) {
414 {
415 auto slot = d_slot->lock();
416
417 size_t k;
418 auto pubAttr = std::make_unique<CK_ATTRIBUTE[]>(pubAttributes.size());
419 auto privAttr = std::make_unique<CK_ATTRIBUTE[]>(pubAttributes.size());
420
421 k = 0;
422 for(P11KitAttribute& attribute : pubAttributes) {
423 attribute.rattr(pubAttr.get()+k);
424 k++;
425 }
426
427 k = 0;
428 for(P11KitAttribute& attribute : privAttributes) {
429 attribute.rattr(privAttr.get()+k);
430 k++;
431 }
432
433 d_err = slot->f()->C_GenerateKeyPair(slot->Session(), mechanism, pubAttr.get(), pubAttributes.size(), privAttr.get(), privAttributes.size(), pubKey, privKey);
434 logError("C_GenerateKeyPair");
435 }
436
437 if (d_err == 0) LoadAttributes();
438
439 return d_err;
440 }
441
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();
446
447 // perform signature
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);
450
451 if (!d_err) {
452 result.assign((char*)buffer, buflen);
453 }
454
455 memset(buffer,0,sizeof buffer);
456 logError("C_Sign");
457 return d_err;
458 }
459
460 int Verify(const std::string& data, const std::string& signature, CK_MECHANISM_PTR mechanism) {
461 auto slot = d_slot->lock();
462
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");
466 return d_err;
467 }
468
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
472
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);
476 if (!d_err) {
477 result.assign((char*)buffer, buflen);
478 }
479 memset(buffer,0,sizeof buffer);
480 logError("C_Digest");
481 return d_err;
482 }
483
484 int DigestInit(Pkcs11Slot& slot, CK_MECHANISM_PTR mechanism) {
485 d_err = slot.f()->C_DigestInit(slot.Session(), mechanism);
486 logError("C_DigestInit");
487 return d_err;
488 }
489
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");
493 return d_err;
494 }
495
496 int DigestKey(std::string& result) {
497 auto slot = d_slot->lock();
498 CK_MECHANISM mech;
499 mech.mechanism = CKM_SHA_1;
500
501 DigestInit(*slot, &mech);
502
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);
508 }
509
510 DigestFinal(*slot, result);
511
512 return d_err;
513 }
514
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
518
519 d_err = slot.f()->C_DigestFinal(slot.Session(), buffer, &buflen);
520 if (!d_err) {
521 result.assign((char*)buffer, buflen);
522 }
523 memset(buffer,0,sizeof buffer);
524 logError("C_DigestFinal");
525 return d_err;
526 }
527
528 int FindObjects2(Pkcs11Slot& slot, const std::vector<P11KitAttribute>& attributes, std::vector<CK_OBJECT_HANDLE>& objects, int maxobjects) {
529 CK_RV rv;
530 size_t k;
531 unsigned long count;
532
533 auto handles = std::make_unique<CK_OBJECT_HANDLE[]>(maxobjects);
534 auto attr = std::make_unique<CK_ATTRIBUTE[]>(attributes.size());
535
536 k = 0;
537 for(const P11KitAttribute& attribute : attributes) {
538 attribute.rattr(attr.get()+k);
539 k++;
540 }
541
542 // perform search
543 d_err = slot.f()->C_FindObjectsInit(slot.Session(), attr.get(), k);
544
545 if (d_err) {
546 logError("C_FindObjectsInit");
547 return d_err;
548 }
549
550 count = maxobjects;
551 rv = d_err = slot.f()->C_FindObjects(slot.Session(), handles.get(), maxobjects, &count);
552 objects.clear();
553
554 if (!rv) {
555 for(k=0;k<count;k++) {
556 objects.push_back((handles.get())[k]);
557 }
558 }
559
560 logError("C_FindObjects");
561
562 d_err = slot.f()->C_FindObjectsFinal(slot.Session());
563 logError("C_FindObjectsFinal");
564
565 return rv;
566 }
567
568 int GetAttributeValue2(Pkcs11Slot& slot, const CK_OBJECT_HANDLE& object, std::vector<P11KitAttribute>& attributes)
569 {
570 size_t k;
571 auto attr = std::make_unique<CK_ATTRIBUTE[]>(attributes.size());
572
573 k = 0;
574 for(P11KitAttribute &attribute : attributes) {
575 attribute.wattr(attr.get()+k);
576 k++;
577 }
578
579 // round 1 - get attribute sizes
580 d_err = slot.f()->C_GetAttributeValue(slot.Session(), object, attr.get(), attributes.size());
581 logError("C_GetAttributeValue");
582 if (d_err) {
583 return d_err;
584 }
585
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);
590 }
591 }
592
593 // round 2 - get actual values
594 d_err = slot.f()->C_GetAttributeValue(slot.Session(), object, attr.get(), attributes.size());
595 logError("C_GetAttributeValue");
596
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);
601 }
602 }
603
604 return d_err;
605 };
606
607 const std::string& Modulus() {
608 return d_modulus;
609 }
610
611 const std::string& Exponent() {
612 return d_exponent;
613 }
614
615 const std::string& ECPoint() {
616 return d_ec_point;
617 }
618
619 const std::string& ECParameters() {
620 return d_ecdsa_params;
621 }
622
623 CK_KEY_TYPE KeyType() {
624 return d_key_type;
625 }
626
627 CK_ULONG Bits() {
628 return d_bits;
629 }
630
631 static std::shared_ptr<Pkcs11Token> GetToken(const std::string& module, const string& tokenId, const std::string& label, const std::string& pub_label);
632 };
633
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;
636
637 CK_RV Pkcs11Slot::HuntSlot(const string& tokenId, CK_SLOT_ID &slotId, _CK_SLOT_INFO* info, CK_FUNCTION_LIST* functions)
638 {
639 CK_RV err;
640 unsigned int i;
641 unsigned long slots;
642 _CK_TOKEN_INFO tinfo;
643
644 // go thru all slots
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);
647 if (err) {
648 g_log<<Logger::Warning<<"C_GetSlotList(CK_FALSE, NULL_PTR, &slots) = " << err << std::endl;
649 return err;
650 }
651
652 // get the actual slot ids
653 std::vector<CK_SLOT_ID> slotIds(slots);
654 err = functions->C_GetSlotList(CK_FALSE, slotIds.data(), &slots);
655 if (err) {
656 g_log<<Logger::Warning<<"C_GetSlotList(CK_FALSE, slotIds, &slots) = " << err << std::endl;
657 return err;
658 }
659
660 // iterate all slots
661 for(i=0;i<slots;i++) {
662 slotId=slotIds[i];
663 if (slotId == static_cast<CK_SLOT_ID>(-1))
664 continue;
665 if ((err = functions->C_GetSlotInfo(slotId, info))) {
666 g_log<<Logger::Warning<<"C_GetSlotList("<<slotId<<", info) = " << err << std::endl;
667 return err;
668 }
669 if ((err = functions->C_GetTokenInfo(slotId, &tinfo))) {
670 g_log<<Logger::Warning<<"C_GetSlotList("<<slotId<<", &tinfo) = " << err << std::endl;
671 return err;
672 }
673 std::string slotName;
674 slotName.assign(reinterpret_cast<char*>(tinfo.label), 32);
675 // trim it
676 boost::trim(slotName);
677
678 if (boost::iequals(slotName, tokenId)) {
679 return 0;
680 }
681 }
682
683 // see if we can find it with slotId
684 try {
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;
688 return err;
689 }
690 g_log<<Logger::Warning<<"Specifying PKCS#11 token by SLOT ID is deprecated and should not be used"<<std::endl;
691 return 0;
692 } catch (...) {
693 return CKR_SLOT_ID_INVALID;
694 }
695 return CKR_SLOT_ID_INVALID;
696 }
697
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;
701 sidx.append("|");
702 sidx.append(tokenId);
703 std::map<std::string, std::shared_ptr<LockGuarded<Pkcs11Slot> > >::iterator slotIter;
704 CK_RV err;
705 CK_FUNCTION_LIST* functions;
706
707 // see if we have slot
708 if ((slotIter = pkcs11_slots.find(sidx)) != pkcs11_slots.end()) {
709 return slotIter->second;
710 }
711
712 #ifdef HAVE_P11KIT1_V2
713 functions = p11_kit_module_for_name(p11_modules, module.c_str());
714 #else
715 functions = p11_kit_registered_name_to_module(module.c_str());
716 #endif
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.
719
720 // try to locate a slot
721 _CK_SLOT_INFO info;
722 CK_SLOT_ID slotId;
723
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));
726 }
727
728 // store slot
729 pkcs11_slots[sidx] = std::make_shared<LockGuarded<Pkcs11Slot>>(Pkcs11Slot(functions, slotId));
730
731 return pkcs11_slots[sidx];
732 }
733
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;
737 tidx.append("|");
738 tidx.append(tokenId);
739 tidx.append("|");
740 tidx.append(label);
741 std::map<std::string, std::shared_ptr<Pkcs11Token> >::iterator tokenIter;
742 if ((tokenIter = pkcs11_tokens.find(tidx)) != pkcs11_tokens.end()) return tokenIter->second;
743
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];
747 }
748
749 Pkcs11Token::Pkcs11Token(const std::shared_ptr<LockGuarded<Pkcs11Slot>>& slot, const std::string& label, const std::string& pub_label) :
750 d_slot(slot),
751 d_bits(0),
752 d_label(label),
753 d_pub_label(pub_label),
754 d_loaded(false),
755 d_err(0)
756 {
757 // open a session
758 if (this->d_slot->lock()->LoggedIn()) LoadAttributes();
759 }
760
761 Pkcs11Token::~Pkcs11Token() {
762 }
763
764 bool PKCS11ModuleSlotLogin(const std::string& module, const string& tokenId, const std::string& pin)
765 {
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);
769 }
770
771 PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(unsigned int algorithm): DNSCryptoKeyEngine(algorithm) {}
772 PKCS11DNSCryptoKeyEngine::~PKCS11DNSCryptoKeyEngine() {}
773 PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(const PKCS11DNSCryptoKeyEngine& orig) : DNSCryptoKeyEngine(orig.d_algorithm) {}
774
775 void PKCS11DNSCryptoKeyEngine::create(unsigned int bits) {
776 std::vector<P11KitAttribute> pubAttr;
777 std::vector<P11KitAttribute> privAttr;
778 CK_MECHANISM mech;
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");
785
786 std::string pubExp("\000\001\000\001", 4); // 65537
787
788 try {
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");
792 }
793
794 mech.pParameter = nullptr;
795 mech.ulParameterLen = 0;
796
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));
807
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");
830
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));
842 } else {
843 throw PDNSException("pkcs11: don't know how make key for algorithm "+std::to_string(d_algorithm));
844 }
845
846
847 if (d_slot->GenerateKeyPair(&mech, pubAttr, privAttr, &pubKey, &privKey)) {
848 throw PDNSException("Keypair generation failed");
849 }
850 };
851
852 std::string PKCS11DNSCryptoKeyEngine::sign(const std::string& msg) const {
853 std::string result;
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");
859
860 CK_MECHANISM mech;
861 mech.mechanism = dnssec2smech[d_algorithm];
862 mech.pParameter = nullptr;
863 mech.ulParameterLen = 0;
864
865 if (mech.mechanism == CKM_ECDSA) {
866 if (d_slot->Sign(this->hash(msg), result, &mech)) throw PDNSException("Could not sign data");
867 } else {
868 if (d_slot->Sign(msg, result, &mech)) throw PDNSException("Could not sign data");
869 }
870 return result;
871 };
872
873 std::string PKCS11DNSCryptoKeyEngine::hash(const std::string& msg) const {
874 std::string result;
875 CK_MECHANISM mech;
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");
884
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) {
889 case 5: {
890 return pdns_sha1sum(msg);
891 }
892 case 8: {
893 return pdns_sha256sum(msg);
894 }
895 case 10: {
896 return pdns_sha512sum(msg);
897 }
898 case 13: {
899 return pdns_sha256sum(msg);
900 }
901 case 14: {
902 return pdns_sha384sum(msg);
903 }
904 };
905 };
906 return result;
907 };
908
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");
915
916 CK_MECHANISM mech;
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);
922 } else {
923 return (d_slot->Verify(msg, signature, &mech) == 0);
924 }
925 };
926
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");
934
935 std::string result;
936 if (d_slot->DigestKey(result) == 0) return result;
937 throw PDNSException("Could not digest key (maybe it's missing?)");
938 };
939
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");
947
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());
951 } else {
952 result.assign(1, 0);
953 uint16_t len=htons(d_slot->Exponent().length());
954 result.append((char*)&len, 2);
955 }
956 result.append(d_slot->Exponent());
957 result.append(d_slot->Modulus());
958 } else {
959 result.append(d_slot->ECPoint());
960 }
961 return result;
962 };
963
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");
970
971 return d_slot->Bits();
972 };
973
974 DNSCryptoKeyEngine::storvector_t PKCS11DNSCryptoKeyEngine::convertToISCVector() const {
975 auto storvect = storvector_t{
976 {"Algorithm", std::to_string(d_algorithm)},
977 {"Engine", d_module},
978 {"Slot", d_slot_id},
979 {"PIN", d_pin},
980 {"Label", d_label},
981 {"PubLabel", d_pub_label},
982 };
983 return storvect;
984 };
985
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"];
995 else
996 d_pub_label = d_label;
997 // validate parameters
998
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?)");
1004 };
1005
1006 std::unique_ptr<DNSCryptoKeyEngine> PKCS11DNSCryptoKeyEngine::maker(unsigned int algorithm)
1007 {
1008 return make_unique<PKCS11DNSCryptoKeyEngine>(algorithm);
1009 }
1010
1011 // this is called during program startup
1012 namespace {
1013 static struct LoaderStruct
1014 {
1015 LoaderStruct()
1016 {
1017 #ifdef HAVE_P11KIT1_V2
1018 p11_modules = p11_kit_modules_load_and_initialize(0);
1019 #else
1020 p11_kit_initialize_registered();
1021 #endif
1022 };
1023 ~LoaderStruct() {
1024 #ifdef HAVE_P11KIT1_V2
1025 p11_kit_modules_release(p11_modules);
1026 #else
1027 p11_kit_finalize_registered();
1028 #endif
1029 };
1030 } loaderPkcs11;
1031 }