};
};
- // representation of slot
- class P11KitSlot {
- private:
- CK_SESSION_HANDLE d_session;
- CK_SLOT_ID d_slot;
- P11KitModule *d_module;
- public:
- P11KitSlot();
- P11KitSlot(CK_SLOT_ID slot, P11KitModule *module);
- P11KitSlot(const P11KitSlot& rhs);
- ~P11KitSlot();
+ class Pkcs11Slot {
+ private:
+ bool d_logged_in;
+ CK_FUNCTION_LIST* d_functions; // module functions
+ CK_SESSION_HANDLE d_session;
+ CK_SLOT_ID d_slot;
+ CK_RV d_err;
+ pthread_mutex_t d_m;
- void SetSlot(CK_SLOT_ID slot);
- void SetModule(P11KitModule *module);
+ void logError(const std::string& operation) const {
+ if (d_err) {
+ std::string msg = boost::str( boost::format("PKCS#11 operation %s failed: %s (0x%X)") % operation % p11_kit_strerror(d_err) % d_err );
+ L<<Logger::Error<< msg << endl;
+ }
+ }
+ public:
+ Pkcs11Slot(CK_FUNCTION_LIST* functions, const CK_SLOT_ID& slot) {
+ CK_TOKEN_INFO tokenInfo;
+ d_slot = slot;
+ d_functions = functions;
+ d_err = 0;
+ d_logged_in = false;
+ pthread_mutex_init(&(this->d_m), NULL);
+ Lock l(&d_m);
+
+ if ((d_err = d_functions->C_OpenSession(this->d_slot, CKF_SERIAL_SESSION|CKF_RW_SESSION, 0, 0, &(this->d_session)))) {
+ logError("C_OpenSession");
+ throw PDNSException("Could not open session");
+ }
+ // check if we need to login
+ if ((d_err = d_functions->C_GetTokenInfo(d_slot, &tokenInfo)) == 0) {
+ d_logged_in = ((tokenInfo.flags && CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED);
+ } else {
+ logError("C_GetTokenInfo");
+ throw PDNSException("Cannot get token info for slot " + boost::lexical_cast<std::string>(slot));
+ }
+ }
- CK_RV OpenSession(CK_FLAGS flags);
- CK_RV CloseSession();
+ bool Login(const std::string& pin) {
+ if (d_logged_in) return true;
- CK_RV GetInfo(CK_SLOT_INFO_PTR info) const;
- CK_RV GetTokenInfo(CK_TOKEN_INFO_PTR info) const;
+ unsigned char *uPin = new unsigned char[pin.size()];
+ memcpy(uPin, pin.c_str(), pin.size());
+ d_err = d_functions->C_Login(this->d_session, CKU_USER, uPin, pin.size());
+ memset(uPin, 0, pin.size());
+ delete [] uPin;
+ logError("C_Login");
- CK_RV Login(const std::string& pin, CK_USER_TYPE user);
- CK_RV Logout();
+ if (d_err == 0) {
+ d_logged_in = true;
+ }
- CK_RV GenerateKeyPair(CK_MECHANISM_PTR mechanism, std::vector<P11KitAttribute>& pubAttributes, std::vector<P11KitAttribute>& privAttributes, CK_OBJECT_HANDLE_PTR pubKey, CK_OBJECT_HANDLE_PTR privKey);
- CK_RV FindObjects(const std::vector<P11KitAttribute>& attributes, std::vector<CK_OBJECT_HANDLE>& objects, CK_ULONG maxobjects) const;
- CK_RV SetAttributeValue(CK_OBJECT_HANDLE object, const std::vector<P11KitAttribute>& attributes);
- CK_RV GetAttributeValue(CK_OBJECT_HANDLE object, std::vector<P11KitAttribute>& attributes) const;
+ return d_logged_in;
+ }
- CK_RV Sign(const std::string& data, std::string& result, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) const;
- CK_RV Verify(const std::string& data, const std::string& result, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) const;
+ bool LoggedIn() const { return d_logged_in; }
- CK_RV Digest(const std::string& data, std::string& result, CK_MECHANISM_PTR mechanism) const;
+ CK_SESSION_HANDLE& Session() { return d_session; }
- CK_RV DigestInit(CK_MECHANISM_PTR mechanism) const;
- CK_RV DigestUpdate(const std::string& data) const;
- CK_RV DigestUpdate(CK_OBJECT_HANDLE key) const;
- CK_RV DigestFinal(std::string& result) const;
+ CK_FUNCTION_LIST* f() { return d_functions; }
+
+ pthread_mutex_t *m() { return &d_m; }
};
- // representation of module (or Engine)
- class P11KitModule
- {
+ class Pkcs11Token {
+ private:
- boost::shared_ptr<Pkcs11Slot> d_slot;
++ std::shared_ptr<Pkcs11Slot> d_slot;
+
+ CK_OBJECT_HANDLE d_public_key;
+ CK_OBJECT_HANDLE d_private_key;
+ CK_KEY_TYPE d_key_type;
+
+ CK_ULONG d_bits;
+ std::string d_exponent;
+ std::string d_modulus;
+ std::string d_ec_point;
+ std::string d_ecdsa_params;
+
+ std::string d_label;
+
+ CK_RV d_err;
+
+ void logError(const std::string& operation) const {
+ if (d_err) {
+ std::string msg = boost::str( boost::format("PKCS#11 operation %s failed: %s (0x%X)") % operation % p11_kit_strerror(d_err) % d_err );
+ L<<Logger::Error<< msg << endl;
+ }
+ }
+
public:
- std::string d_module;
- CK_FUNCTION_LIST_PTR functions;
- Pkcs11Token(const boost::shared_ptr<Pkcs11Slot>& slot, const std::string& label);
++ Pkcs11Token(const std::shared_ptr<Pkcs11Slot>& slot, const std::string& label);
+ ~Pkcs11Token();
+
+ bool Login(const std::string& pin) {
+ if (pin.empty()) return CKR_PIN_INVALID; // no empty pin.
+ Lock l(d_slot->m());
- P11KitModule() {}
+ if (d_slot->Login(pin) == true) {
+ LoadAttributes();
+ }
- P11KitModule(const std::string& module) {
- this->d_module = module;
+ return LoggedIn();
}
- P11KitModule(const P11KitModule& rhs) {
- functions = rhs.functions;
- d_module = rhs.d_module;
+ bool LoggedIn() const { return d_slot->LoggedIn(); }
+
+ void LoadAttributes() {
+ std::vector<P11KitAttribute> attr;
+ std::vector<CK_OBJECT_HANDLE> key;
+ attr.push_back(P11KitAttribute(CKA_CLASS, (unsigned long)CKO_PRIVATE_KEY));
+ // attr.push_back(P11KitAttribute(CKA_SIGN, (char)CK_TRUE));
+ attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
+ FindObjects2(attr, key, 1);
+ if (key.size() == 0) {
+ L<<Logger::Warning<<"Cannot load PCKS#11 private key "<<d_label<<std::endl;;
+ return;
+ }
+ d_private_key = key[0];
+ attr.clear();
+ attr.push_back(P11KitAttribute(CKA_CLASS, (unsigned long)CKO_PUBLIC_KEY));
+ // attr.push_back(P11KitAttribute(CKA_VERIFY, (char)CK_TRUE));
+ attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
+ FindObjects2(attr, key, 1);
+ if (key.size() == 0) {
+ L<<Logger::Warning<<"Cannot load PCKS#11 public key "<<d_label<<std::endl;
+ return;
+ }
+ d_public_key = key[0];
+
+ attr.clear();
+ attr.push_back(P11KitAttribute(CKA_KEY_TYPE, 0UL));
+
+ if (GetAttributeValue2(d_public_key, attr)==0) {
+ d_key_type = attr[0].ulong();
+ if (d_key_type == CKK_RSA) {
+ attr.clear();
+ attr.push_back(P11KitAttribute(CKA_MODULUS, ""));
+ attr.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT, ""));
+ attr.push_back(P11KitAttribute(CKA_MODULUS_BITS, 0UL));
+
+ if (!GetAttributeValue2(d_public_key, attr)) {
+ d_modulus = attr[0].str();
+ d_exponent = attr[1].str();
+ d_bits = attr[2].ulong();
+ } else {
+ throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_label);
+ }
+ } else if (d_key_type == CKK_EC || d_key_type == CKK_ECDSA) {
+ attr.clear();
+ attr.push_back(P11KitAttribute(CKA_ECDSA_PARAMS, ""));
+ attr.push_back(P11KitAttribute(CKA_EC_POINT, ""));
+ if (!GetAttributeValue2(d_public_key, attr)) {
+ d_ecdsa_params = attr[0].str();
+ if (d_ecdsa_params == "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07") d_bits = 256;
+ if (d_ecdsa_params == "\x06\x05\x2b\x81\x04\x00\x22") d_bits = 384;
+ d_ec_point = attr[1].str();
+ } else {
+ throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_label);
+ }
+ } else {
+ throw PDNSException("Cannot determine type for PCKS#11 public key " + d_label);
+ }
+ } else {
+ throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_label);
+ }
}
- void setModule(const std::string& module) {
- this->d_module = module;
- };
+ int GenerateKeyPair(CK_MECHANISM_PTR mechanism, std::vector<P11KitAttribute>& pubAttributes, std::vector<P11KitAttribute>& privAttributes, CK_OBJECT_HANDLE_PTR pubKey, CK_OBJECT_HANDLE_PTR privKey) {
+ Lock l(d_slot->m());
- // basically get the function list
- bool initialize() {
- #ifdef HAVE_P11KIT1_V2
- functions = p11_kit_module_for_name(p11_modules, d_module.c_str());
- #else
- functions = p11_kit_registered_name_to_module(d_module.c_str());
- #endif
- if (functions == NULL) return false;
- return true;
- };
+ size_t k;
+ CK_ATTRIBUTE_PTR pubAttr, privAttr;
+ pubAttr = new CK_ATTRIBUTE[pubAttributes.size()];
+ privAttr = new CK_ATTRIBUTE[privAttributes.size()];
- // convenience method + checking that slot exists
- bool GetSlot(CK_SLOT_ID slotId, P11KitSlot &slot) {
- _CK_SLOT_INFO info;
- if (this->functions->C_GetSlotInfo(slotId, &info)) {
- return false;
+ k = 0;
+ BOOST_FOREACH(P11KitAttribute& attribute, pubAttributes) {
+ attribute.rattr(pubAttr+k);
+ k++;
}
- slot.SetSlot(slotId);
- slot.SetModule(this);
- return true;
- };
- };
- P11KitSlot::P11KitSlot() { d_module = NULL; };
+ k = 0;
+ BOOST_FOREACH(P11KitAttribute& attribute, privAttributes) {
+ attribute.rattr(privAttr+k);
+ k++;
+ }
- P11KitSlot::P11KitSlot(CK_SLOT_ID slot, P11KitModule *module)
- {
- this->d_slot = slot;
- this->d_module = module;
- }
+ d_err = this->d_slot->f()->C_GenerateKeyPair(d_slot->Session(), mechanism, pubAttr, pubAttributes.size(), privAttr, privAttributes.size(), pubKey, privKey);
+ logError("C_GenerateKeyPair");
+ delete [] pubAttr;
+ delete [] privAttr;
- P11KitSlot::P11KitSlot(const P11KitSlot &rhs)
- {
- this->d_slot = rhs.d_slot;
- this->d_module = rhs.d_module;
- this->d_session = rhs.d_session;
- }
+ if (d_err == 0) LoadAttributes();
- P11KitSlot::~P11KitSlot()
- {
- if (this->d_module && this->d_session)
- this->d_module->functions->C_CloseSession(this->d_session);
- }
+ return d_err;
+ }
- // DO NOT CALL THIS ON YOUR OWN
- void P11KitSlot::SetSlot(CK_SLOT_ID slot) {
- this->d_slot = slot;
- }
+ int Sign(const std::string& data, std::string& result, CK_MECHANISM_PTR mechanism) {
+ Lock l(d_slot->m());
- // DO NOT CALL THIS ON YOUR OWN
- void P11KitSlot::SetModule(P11KitModule *module) {
- this->d_module = module;
- }
+ CK_BYTE buffer[1024];
+ CK_ULONG buflen = sizeof buffer; // should be enough for most signatures.
- // Create new session, mostly uses CKF_SERIAL_SESSION (which is mandatory flag)
- // Another flag you can pass is CFK_RW_SESSION
- CK_RV P11KitSlot::OpenSession(CK_FLAGS flags)
- {
- if (!this->d_module) return 0xff;
- return this->d_module->functions->C_OpenSession(this->d_slot, flags, 0, 0, &(this->d_session));
- }
+ // perform signature
+ if ((d_err = this->d_slot->f()->C_SignInit(d_slot->Session(), mechanism, d_private_key))) { logError("C_SignInit"); return d_err; }
+ d_err = this->d_slot->f()->C_Sign(d_slot->Session(), (unsigned char*)data.c_str(), data.size(), buffer, &buflen);
- CK_RV P11KitSlot::CloseSession()
- {
- if (!this->d_module) return 0xff;
- CK_RV rv = this->d_module->functions->C_CloseSession(this->d_session);
- this->d_session = 0;
- return rv;
- }
+ if (!d_err) {
+ result.assign((char*)buffer, buflen);
+ }
- CK_RV P11KitSlot::GetInfo(CK_SLOT_INFO_PTR info) const
- {
- if (!this->d_module) return 0xff;
- return this->d_module->functions->C_GetSlotInfo(this->d_slot, info);
- }
+ memset(buffer,0,sizeof buffer);
+ logError("C_Sign");
+ return d_err;
+ }
- CK_RV P11KitSlot::GetTokenInfo(CK_TOKEN_INFO_PTR info) const
- {
- if (!this->d_module) return 0xff;
- return this->d_module->functions->C_GetTokenInfo(this->d_slot, info);
- }
+ int Verify(const std::string& data, const std::string& signature, CK_MECHANISM_PTR mechanism) {
+ Lock l(d_slot->m());
- CK_RV P11KitSlot::Login(const std::string& pin, CK_USER_TYPE user)
- {
- if (!this->d_module) return 0xff;
- CK_RV rv;
- unsigned char *pPin;
- pPin = new unsigned char[pin.size()];
- pin.copy(reinterpret_cast<char*>(pPin), pin.size());
- rv = this->d_module->functions->C_Login(this->d_session, user, pPin, pin.size());
- delete [] pPin;
- return rv;
- }
+ if ((d_err = this->d_slot->f()->C_VerifyInit(d_slot->Session(), mechanism, d_public_key))) { logError("C_VerifyInit"); return d_err; }
+ 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());
+ logError("C_Verify");
+ return d_err;
+ }
- CK_RV P11KitSlot::Logout()
- {
- if (!this->d_module) return 0xff;
- return this->d_module->functions->C_Logout(this->d_slot);
- }
+ int Digest(const std::string& data, std::string& result, CK_MECHANISM_PTR mechanism) {
+ Lock l(d_slot->m());
- CK_RV P11KitSlot::GenerateKeyPair(CK_MECHANISM_PTR mechanism, std::vector<P11KitAttribute>& pubAttributes, std::vector<P11KitAttribute>& privAttributes, CK_OBJECT_HANDLE_PTR pubKey, CK_OBJECT_HANDLE_PTR privKey) {
- if (!this->d_module) return 0xff;
+ CK_BYTE buffer[1024];
+ CK_ULONG buflen = sizeof buffer; // should be enough for most digests
+ if ((d_err = this->d_slot->f()->C_DigestInit(d_slot->Session(), mechanism))) { logError("C_DigestInit"); return d_err; }
+ d_err = this->d_slot->f()->C_Digest(d_slot->Session(), (unsigned char*)data.c_str(), data.size(), buffer, &buflen);
+ if (!d_err) {
+ result.assign((char*)buffer, buflen);
+ }
+ memset(buffer,0,sizeof buffer);
+ logError("C_Digest");
+ return d_err;
+ }
- CK_RV rv;
- size_t k;
- CK_ATTRIBUTE_PTR pubAttr, privAttr;
- pubAttr = new CK_ATTRIBUTE[pubAttributes.size()];
- privAttr = new CK_ATTRIBUTE[privAttributes.size()];
-
- k = 0;
- BOOST_FOREACH(P11KitAttribute& attribute, pubAttributes) {
- attribute.rattr(pubAttr+k);
- k++;
- }
+ int DigestInit(CK_MECHANISM_PTR mechanism) {
+ d_err = d_slot->f()->C_DigestInit(d_slot->Session(), mechanism);
+ logError("C_DigestInit");
+ return d_err;
+ }
- k = 0;
- BOOST_FOREACH(P11KitAttribute& attribute, privAttributes) {
- attribute.rattr(privAttr+k);
- k++;
- }
+ int DigestUpdate(const std::string& data) {
+ d_err = d_slot->f()->C_DigestUpdate(d_slot->Session(), (unsigned char*)data.c_str(), data.size());
+ logError("C_DigestUpdate");
+ return d_err;
+ }
- rv = this->d_module->functions->C_GenerateKeyPair(d_session, mechanism, pubAttr, pubAttributes.size(), privAttr, privAttributes.size(), pubKey, privKey);
+ int DigestKey(std::string& result) {
+ Lock l(d_slot->m());
+ CK_MECHANISM mech;
+ mech.mechanism = CKM_SHA_1;
- delete [] pubAttr;
- delete [] privAttr;
+ DigestInit(&mech);
- return rv;
- }
+ if (d_key_type == CKK_RSA) {
+ DigestUpdate(d_modulus);
+ DigestUpdate(d_exponent);
+ } else if (d_key_type == CKK_EC || d_key_type == CKK_ECDSA) {
+ DigestUpdate(d_ec_point);
+ }
- // Finds object(s) that match exactly to attributes
- CK_RV P11KitSlot::FindObjects(const std::vector<P11KitAttribute>& attributes, std::vector<CK_OBJECT_HANDLE>& objects, unsigned long maxobjects) const
- {
- if (!this->d_module) return 0xff;
- CK_RV rv;
- size_t k;
- unsigned long count;
- CK_ATTRIBUTE_PTR attr;
- CK_OBJECT_HANDLE_PTR handles = new CK_OBJECT_HANDLE[maxobjects];
- attr = new CK_ATTRIBUTE[attributes.size()];
-
- k = 0;
- BOOST_FOREACH(const P11KitAttribute& attribute, attributes) {
- attribute.rattr(attr+k);
- k++;
- }
+ DigestFinal(result);
- // perform search
- rv = this->d_module->functions->C_FindObjectsInit(d_session, attr, k);
+ return d_err;
+ }
- if (rv) {
- delete [] attr;
- delete [] handles;
- return rv;
- }
+ int DigestFinal(std::string& result) {
+ CK_BYTE buffer[1024] = {0};
+ CK_ULONG buflen = sizeof buffer; // should be enough for most digests
+ d_err = d_slot->f()->C_DigestFinal(d_slot->Session(), buffer, &buflen);
+ if (!d_err) {
+ result.assign((char*)buffer, buflen);
+ }
+ memset(buffer,0,sizeof buffer);
+ logError("C_DigestFinal");
+ return d_err;
+ }
+
+ int FindObjects(const std::vector<P11KitAttribute>& attributes, std::vector<CK_OBJECT_HANDLE>& objects, int maxobjects) {
+ Lock l(d_slot->m());
+ return FindObjects2(attributes, objects, maxobjects);
+ }
- count = maxobjects;
- rv = this->d_module->functions->C_FindObjects(d_session, handles, maxobjects, &count);
+ int FindObjects2(const std::vector<P11KitAttribute>& attributes, std::vector<CK_OBJECT_HANDLE>& objects, int maxobjects) {
+ CK_RV rv;
+ size_t k;
+ unsigned long count;
- if (!rv) {
- objects.clear();
- for(k=0;k<count;k++) {
- objects.push_back(handles[k]);
+ CK_ATTRIBUTE_PTR attr;
+ CK_OBJECT_HANDLE_PTR handles = new CK_OBJECT_HANDLE[maxobjects];
+ attr = new CK_ATTRIBUTE[attributes.size()];
+
+ k = 0;
+ BOOST_FOREACH(const P11KitAttribute& attribute, attributes) {
+ attribute.rattr(attr+k);
+ k++;
+ }
+
+ // perform search
+ d_err = this->d_slot->f()->C_FindObjectsInit(d_slot->Session(), attr, k);
+
+ if (d_err) {
+ delete [] attr;
+ delete [] handles;
+ logError("C_FindObjectsInit");
+ return d_err;
+ }
+
+ count = maxobjects;
+ rv = d_err = this->d_slot->f()->C_FindObjects(d_slot->Session(), handles, maxobjects, &count);
+ objects.clear();
+
+ if (!rv) {
+ for(k=0;k<count;k++) {
+ objects.push_back(handles[k]);
+ }
+ }
+
+ logError("C_FindObjects");
+
+ delete [] attr;
+ delete [] handles;
+
+ d_err = this->d_slot->f()->C_FindObjectsFinal(d_slot->Session());
+ logError("C_FindObjectsFinal");
+
+ return rv;
}
- }
- delete [] attr;
- delete [] handles;
+ int GetAttributeValue(const CK_OBJECT_HANDLE& object, std::vector<P11KitAttribute>& attributes)
+ {
+ Lock l(d_slot->m());
+ return GetAttributeValue2(object, attributes);
+ }
- this->d_module->functions->C_FindObjectsFinal(d_session);
+ int GetAttributeValue2(const CK_OBJECT_HANDLE& object, std::vector<P11KitAttribute>& attributes)
+ {
+ size_t k;
+ CK_ATTRIBUTE_PTR attr;
+ attr = new CK_ATTRIBUTE[attributes.size()];
- return rv;
- };
+ k = 0;
+ BOOST_FOREACH(P11KitAttribute &attribute, attributes) {
+ attribute.wattr(attr+k);
+ k++;
+ }
- // TODO: Untested codepath
- CK_RV P11KitSlot::SetAttributeValue(CK_OBJECT_HANDLE object, const std::vector<P11KitAttribute>& attributes)
- {
- if (!this->d_module) return 0xff;
- CK_RV rv;
- size_t k;
- CK_ATTRIBUTE_PTR attr;
- attr = new CK_ATTRIBUTE[attributes.size()];
-
- k = 0;
- BOOST_FOREACH(const P11KitAttribute &attribute, attributes) {
- attribute.rattr(attr+k);
- k++;
- }
+ // round 1 - get attribute sizes
+ d_err = d_slot->f()->C_GetAttributeValue(d_slot->Session(), object, attr, attributes.size());
+ logError("C_GetAttributeValue");
+ if (d_err) {
+ delete [] attr;
+ return d_err;
+ }
- rv = this->d_module->functions->C_SetAttributeValue(d_session, object, attr, attributes.size());
+ // then allocate memory
+ for(size_t k=0; k < attributes.size(); k++) {
+ if (attributes[k].valueType() == Attribute_String) {
+ attr[k].pValue = attributes[k].allocate(attr[k].ulValueLen);
+ }
+ }
- delete [] attr;
- return rv;
- }
+ // round 2 - get actual values
+ d_err = d_slot->f()->C_GetAttributeValue(d_slot->Session(), object, attr, attributes.size());
+ logError("C_GetAttributeValue");
- CK_RV P11KitSlot::GetAttributeValue(CK_OBJECT_HANDLE object, std::vector<P11KitAttribute>& attributes) const
- {
- if (!this->d_module) return 0xff;
- CK_RV rv;
- size_t k;
- CK_ATTRIBUTE_PTR attr;
- attr = new CK_ATTRIBUTE[attributes.size()];
-
- k = 0;
- BOOST_FOREACH(P11KitAttribute &attribute, attributes) {
- attribute.wattr(attr+k);
- k++;
- }
+ // copy values to map and release allocated memory
+ for(size_t k=0; k < attributes.size(); k++) {
+ if (attributes[k].valueType() == Attribute_String) {
+ attributes[k].commit(attr[k].ulValueLen);
+ }
+ }
- // round 1 - get attribute sizes
- rv = this->d_module->functions->C_GetAttributeValue(d_session, object, attr, attributes.size());
+ delete [] attr;
- if (rv) {
- delete [] attr;
- return rv;
- }
+ return d_err;
+ };
- // then allocate memory
- for(size_t k=0; k < attributes.size(); k++) {
- if (attributes[k].valueType() == Attribute_String) {
- attr[k].pValue = attributes[k].allocate(attr[k].ulValueLen);
+ const std::string& Modulus() {
+ return d_modulus;
}
- }
- // round 2 - get actual values
- rv = this->d_module->functions->C_GetAttributeValue(d_session, object, attr, attributes.size());
+ const std::string& Exponent() {
+ return d_exponent;
+ }
- // copy values to map and release allocated memory
- for(size_t k=0; k < attributes.size(); k++) {
- if (attributes[k].valueType() == Attribute_String) {
- attributes[k].commit(attr[k].ulValueLen);
+ const std::string& ECPoint() {
+ return d_ec_point;
+ }
+
+ const std::string& ECParameters() {
+ return d_ecdsa_params;
+ }
+
+ CK_KEY_TYPE KeyType() {
+ return d_key_type;
}
- }
- delete [] attr;
+ CK_ULONG Bits() {
+ return d_bits;
+ }
- return rv;
- static boost::shared_ptr<Pkcs11Token> GetToken(const std::string& module, const CK_SLOT_ID& slotId, const std::string& label);
++ static std::shared_ptr<Pkcs11Token> GetToken(const std::string& module, const CK_SLOT_ID& slotId, const std::string& label);
};
- CK_RV P11KitSlot::Sign(const std::string& data, std::string& result, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) const
- {
- if (!this->d_module) return 0xff;
- CK_RV rv;
- CK_BYTE buffer[1024];
- CK_ULONG buflen = sizeof buffer; // should be enough for most signatures.
-
- // perform signature
- if ((rv = this->d_module->functions->C_SignInit(d_session, mechanism, key))) return rv; // well that failed.
- rv = this->d_module->functions->C_Sign(d_session, (unsigned char*)data.c_str(), data.size(), buffer, &buflen);
- if (!rv) {
- result.assign((char*)buffer, buflen);
-static std::map<std::string, boost::shared_ptr<Pkcs11Slot> > pkcs11_slots;
-static std::map<std::string, boost::shared_ptr<Pkcs11Token> > pkcs11_tokens;
++static std::map<std::string, std::shared_ptr<Pkcs11Slot> > pkcs11_slots;
++static std::map<std::string, std::shared_ptr<Pkcs11Token> > pkcs11_tokens;
+
-boost::shared_ptr<Pkcs11Token> Pkcs11Token::GetToken(const std::string& module, const CK_SLOT_ID& slotId, const std::string& label) {
++std::shared_ptr<Pkcs11Token> Pkcs11Token::GetToken(const std::string& module, const CK_SLOT_ID& slotId, const std::string& label) {
+ // see if we can find module
+ std::string tidx = module;
+ tidx.append("|");
+ tidx.append(boost::lexical_cast<std::string>(slotId));
+ std::string sidx = tidx;
+ tidx.append("|");
+ tidx.append(label);
- std::map<std::string, boost::shared_ptr<Pkcs11Token> >::iterator tokenIter;
- std::map<std::string, boost::shared_ptr<Pkcs11Slot> >::iterator slotIter;
++ std::map<std::string, std::shared_ptr<Pkcs11Token> >::iterator tokenIter;
++ std::map<std::string, std::shared_ptr<Pkcs11Slot> >::iterator slotIter;
+ CK_RV err;
+ CK_FUNCTION_LIST* functions;
+
+ if ((tokenIter = pkcs11_tokens.find(tidx)) != pkcs11_tokens.end()) return tokenIter->second;
+
+ // see if we have slot
+ if ((slotIter = pkcs11_slots.find(sidx)) != pkcs11_slots.end()) {
+ pkcs11_tokens[tidx] = boost::make_shared<Pkcs11Token>(slotIter->second, label);
+ return pkcs11_tokens[tidx];
}
- memset(buffer,0,sizeof buffer);
- return rv;
- };
+ #ifdef HAVE_P11KIT1_V2
+ functions = p11_kit_module_for_name(p11_modules, module.c_str());
+ #else
+ functions = p11_kit_registered_name_to_module(module.c_str());
+ #endif
+ if (functions == NULL) throw PDNSException("Cannot find PKCS#11 module " + module);
+ functions->C_Initialize(NULL); // initialize the module in case it hasn't been done yet.
- CK_RV P11KitSlot::Verify(const std::string& data, const std::string& signature, CK_MECHANISM_PTR mechanism, CK_OBJECT_HANDLE key) const
- {
- if (!this->d_module) return 0xff;
- CK_RV rv;
- if ((rv = this->d_module->functions->C_VerifyInit(d_session, mechanism, key))) return rv;
- rv = this->d_module->functions->C_Verify(d_session, (unsigned char*)data.c_str(), data.size(), (unsigned char*)signature.c_str(), signature.size());
- return rv;
- };
+ // try to locate a slot
+ _CK_SLOT_INFO info;
+ unsigned long slots;
- CK_RV P11KitSlot::Digest(const std::string& data, std::string& result, CK_MECHANISM_PTR mechanism) const
- {
- if (!this->d_module) return 0xff;
- CK_RV rv;
- CK_BYTE buffer[1024];
- CK_ULONG buflen = sizeof buffer; // should be enough for most digests
- if ((rv = this->d_module->functions->C_DigestInit(d_session, mechanism))) return rv;
- rv = this->d_module->functions->C_Digest(d_session, (unsigned char*)data.c_str(), data.size(), buffer, &buflen);
- if (!rv) {
- result.assign((char*)buffer, buflen);
+ // this is required by certain tokens, otherwise C_GetSlotInfo will not return a token
+ err = functions->C_GetSlotList(CK_FALSE, NULL_PTR, &slots);
+ if (err)
+ L<<Logger::Warning<<"C_GetSlotList(CK_FALSE, NULL_PTR, &slots) = " << err << std::endl;
+
+ if ((err = functions->C_GetSlotInfo(slotId, &info))) {
+ throw PDNSException(std::string("Cannot find PKCS#11 slot ") + boost::lexical_cast<std::string>(slotId) + std::string(" on module ") + module + std::string(": error code ") + boost::lexical_cast<std::string>(err));
}
- memset(buffer,0,sizeof buffer);
- return rv;
- };
+ // store slot
+ pkcs11_slots[sidx] = boost::make_shared<Pkcs11Slot>(functions, slotId);
- CK_RV P11KitSlot::DigestInit(CK_MECHANISM_PTR mechanism) const
- {
- if (!this->d_module) return 0xff;
- return this->d_module->functions->C_DigestInit(d_session, mechanism);
- }
+ // looks ok to me.
+ pkcs11_tokens[tidx] = boost::make_shared<Pkcs11Token>(pkcs11_slots[sidx], label);
- CK_RV P11KitSlot::DigestUpdate(const std::string& data) const
- {
- if (!this->d_module) return 0xff;
- return this->d_module->functions->C_DigestUpdate(d_session, (unsigned char*)data.c_str(), data.size());
+ return pkcs11_tokens[tidx];
}
- CK_RV P11KitSlot::DigestUpdate(CK_OBJECT_HANDLE key) const
- {
- if (!this->d_module) return 0xff;
- return this->d_module->functions->C_DigestKey(d_session, key);
- }
-
- CK_RV P11KitSlot::DigestFinal(std::string& result) const
- {
- if (!this->d_module) return 0xff;
- CK_RV rv;
- CK_BYTE buffer[1024];
- CK_ULONG buflen = sizeof buffer; // should be enough for most digests
- rv = this->d_module->functions->C_DigestFinal(d_session, buffer, &buflen);
- if (!rv) {
- result.assign((char*)buffer, buflen);
- }
- memset(buffer,0,sizeof buffer);
- return rv;
-Pkcs11Token::Pkcs11Token(const boost::shared_ptr<Pkcs11Slot>& slot, const std::string& label) {
++Pkcs11Token::Pkcs11Token(const std::shared_ptr<Pkcs11Slot>& slot, const std::string& label) {
+ // open a session
+ this->d_bits = 0;
+ this->d_slot = slot;
+ this->d_label = label;
+ this->d_err = 0;
+ Lock l(d_slot->m());
+ if (this->d_slot->LoggedIn()) LoadAttributes();
}
- // map between engine names and engines
- static std::map<std::string, P11KitModule> pkcs11_engines;
- // map between engine names and slots (not used now)
- //static std::map<std::string, CK_SLOT_ID> pkcs11_slots;
-
- static bool pkcs11_GetSlot(const std::string& engine, CK_SLOT_ID slotId, const std::string& pin, CK_FLAGS flags, P11KitSlot& slot)
- {
- CK_RV rv;
- if (engine.empty()) return false;
-
- // open module if necessary
- if (pkcs11_engines.find(engine) == pkcs11_engines.end()) {
- P11KitModule module(engine);
- if (module.initialize() == false) {
- throw PDNSException("Cannot initialize or unknown PKCS#11 engine " + engine);
- }
- pkcs11_engines[engine] = module;
- }
- pkcs11_engines[engine].GetSlot(slotId, slot);
- rv = slot.OpenSession(flags);
- if (rv) {
- return false;
- };
- rv = slot.Login(pin, CKU_USER);
- if (rv) {
- L<<Logger::Error<<"Login failed for " << engine << " slot " << slotId << ": " << rv <<std::endl;
- };
- return rv == 0;
+ Pkcs11Token::~Pkcs11Token() {
}
PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(unsigned int algorithm): DNSCryptoKeyEngine(algorithm) {}
CK_MECHANISM mech;
CK_OBJECT_HANDLE pubKey, privKey;
CK_RV rv;
- P11KitSlot d_slot;
- pkcs11_GetSlot(d_engine, d_slot_id, d_pin, CKF_SERIAL_SESSION|CKF_RW_SESSION, d_slot);
- boost::shared_ptr<Pkcs11Token> d_slot;
++ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
std::string pubExp("\000\001\000\001", 4); // 65537
-
+
pubAttr.push_back(P11KitAttribute(CKA_CLASS, (unsigned long)CKO_PUBLIC_KEY));
pubAttr.push_back(P11KitAttribute(CKA_KEY_TYPE, (unsigned long)CKK_RSA));
pubAttr.push_back(P11KitAttribute(CKA_TOKEN, (char)CK_TRUE));
}
};
- std::string PKCS11DNSCryptoKeyEngine::sign(const std::string& msg) const {
+ std::string PKCS11DNSCryptoKeyEngine::sign(const std::string& msg) const {
std::string result;
- std::vector<CK_OBJECT_HANDLE> key;
- std::vector<P11KitAttribute> attr;
- P11KitSlot d_slot;
- pkcs11_GetSlot(d_engine, d_slot_id, d_pin, CKF_SERIAL_SESSION, d_slot);
- // find key that can be used for signing
- attr.push_back(P11KitAttribute(CKA_SIGN, (char)CK_TRUE));
- attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
- d_slot.FindObjects(attr, key, 1);
- // hopefully we have a key
- if (key.size() == 0) return "";
- // choose mech
- boost::shared_ptr<Pkcs11Token> d_slot;
++ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
CK_MECHANISM mech;
mech.mechanism = dnssec2smech[d_algorithm];
mech.pParameter = NULL;
mech.mechanism = dnssec2hmech[d_algorithm];
mech.pParameter = NULL;
mech.ulParameterLen = 0;
- P11KitSlot d_slot;
- pkcs11_GetSlot(d_engine, d_slot_id, d_pin, CKF_SERIAL_SESSION, d_slot);
- boost::shared_ptr<Pkcs11Token> d_slot;
++ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
- if (d_slot.Digest(msg, result, &mech)) {
+ if (d_slot->Digest(msg, result, &mech)) {
// FINE! I'll do this myself, then, shall I?
switch(d_algorithm) {
case 5: {
};
bool PKCS11DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const {
- bool result;
- std::vector<CK_OBJECT_HANDLE> key;
- std::vector<P11KitAttribute> attr;
- // find a key that can be used to verify signatures
- attr.push_back(P11KitAttribute(CKA_VERIFY, (char)CK_TRUE));
- attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
- P11KitSlot d_slot;
- pkcs11_GetSlot(d_engine, d_slot_id, d_pin, CKF_SERIAL_SESSION, d_slot);
-
- d_slot.FindObjects(attr, key, 1);
- // hopefully we have a key
- if (key.size() == 0) return "";
- // choose mech
- boost::shared_ptr<Pkcs11Token> d_slot;
++ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
CK_MECHANISM mech;
mech.mechanism = dnssec2smech[d_algorithm];
mech.pParameter = NULL;
mech.ulParameterLen = 0;
- result = d_slot.Verify(msg, signature, &mech, key[0]);
- return result;
+ if (mech.mechanism == CKM_ECDSA) {
+ return (d_slot->Verify(this->hash(msg), signature, &mech)==0);
+ } else {
+ return (d_slot->Verify(msg, signature, &mech) == 0);
+ }
};
- std::string PKCS11DNSCryptoKeyEngine::getPubKeyHash() const {
- std::string result = "";
- std::vector<CK_OBJECT_HANDLE> key;
- std::vector<P11KitAttribute> attr;
+ std::string PKCS11DNSCryptoKeyEngine::getPubKeyHash() const {
// find us a public key
- attr.push_back(P11KitAttribute(CKA_CLASS, CKO_PUBLIC_KEY));
- attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
- P11KitSlot d_slot;
- pkcs11_GetSlot(d_engine, d_slot_id, d_pin, CKF_SERIAL_SESSION, d_slot);
-
- d_slot.FindObjects(attr, key, 1);
- if (key.size() > 0) {
- attr.clear();
- attr.push_back(P11KitAttribute(CKA_MODULUS, ""));
- attr.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT, ""));
- if (d_slot.GetAttributeValue(key[0], attr) == 0) {
- CK_MECHANISM mech;
- mech.mechanism = CKM_SHA_1;
- d_slot.DigestInit(&mech);
- d_slot.DigestUpdate(attr[0].str());
- d_slot.DigestUpdate(attr[1].str());
- d_slot.DigestFinal(result);
- }
- }
- return result;
- boost::shared_ptr<Pkcs11Token> d_slot;
++ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ std::string result;
+ if (d_slot->DigestKey(result) == 0) return result;
+ throw PDNSException("Could not digest key (maybe it's missing?)");
};
std::string PKCS11DNSCryptoKeyEngine::getPublicKeyString() const {
std::string result("");
- std::vector<CK_OBJECT_HANDLE> key;
- std::vector<P11KitAttribute> attr;
- attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
- P11KitSlot d_slot;
- pkcs11_GetSlot(d_engine, d_slot_id, d_pin, CKF_SERIAL_SESSION, d_slot);
-
- d_slot.FindObjects(attr, key, 1);
- if (key.size() > 0) {
- attr.clear();
- attr.push_back(P11KitAttribute(CKA_MODULUS, ""));
- attr.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT, ""));
- if (d_slot.GetAttributeValue(key[0], attr) == 0) {
- if(attr[1].str().length() < 255)
- result.assign(1, (char) (unsigned int) attr[1].str().length());
- else {
- result.assign(1, 0);
- uint16_t len=htons(attr[1].str().length());
- result.append((char*)&len, 2);
- }
- result.append(attr[1].str());
- result.append(attr[0].str());
- }
- // } else {
- // std::cerr << "Could not find key" << std::endl;
- }
- return result;
- boost::shared_ptr<Pkcs11Token> d_slot;
++ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ if (d_slot->KeyType() == CKK_RSA) {
+ if (d_slot->Exponent().length() < 255) {
+ result.assign(1, (char) (unsigned int) d_slot->Exponent().length());
+ } else {
+ result.assign(1, 0);
+ uint16_t len=htons(d_slot->Exponent().length());
+ result.append((char*)&len, 2);
+ }
+ result.append(d_slot->Exponent());
+ result.append(d_slot->Modulus());
+ } else {
+ result.append(d_slot->ECPoint());
+ }
+ return result;
};
int PKCS11DNSCryptoKeyEngine::getBits() const {
- int bits = -1;
- std::vector<CK_OBJECT_HANDLE> key;
- std::vector<P11KitAttribute> attr;
- attr.push_back(P11KitAttribute(CKA_CLASS, CKO_PUBLIC_KEY));
- attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
- P11KitSlot d_slot;
- pkcs11_GetSlot(d_engine, d_slot_id, d_pin, CKF_SERIAL_SESSION, d_slot);
-
- // std::cerr << "Looking for " << d_label << " from " << d_slot_id << std::endl;
-
- d_slot.FindObjects(attr, key, 1);
- if (key.size() > 0) {
- attr.clear();
- attr.push_back(P11KitAttribute(CKA_MODULUS_BITS, 0UL));
- if (d_slot.GetAttributeValue(key[0], attr) == 0) {
- bits = static_cast<int>(attr[0].ulong());
- }
- // } else {
- // std::cerr << "Could not find key" << std::endl;
- }
- return bits;
- boost::shared_ptr<Pkcs11Token> d_slot;
++ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ return d_slot->Bits();
};
- DNSCryptoKeyEngine::storvector_t PKCS11DNSCryptoKeyEngine::convertToISCVector() const {
+ DNSCryptoKeyEngine::storvector_t PKCS11DNSCryptoKeyEngine::convertToISCVector() const {
storvector_t storvect;
typedef std::vector<std::pair<std::string, std::string> > outputs_t;
outputs_t outputs;
return storvect;
};
- boost::shared_ptr<Pkcs11Token> d_slot;
+ void PKCS11DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, stormap_t& stormap) {
+ drc.d_algorithm = atoi(stormap["algorithm"].c_str());
+ d_module = stormap["engine"];
+ d_slot_id = atoi(stormap["slot"].c_str());
+ d_pin = stormap["pin"];
+ d_label = stormap["label"];
+ // validate parameters
+
++ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_pin != "" && d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Could not log in to token (PIN wrong?)");
+ };
+
DNSCryptoKeyEngine* PKCS11DNSCryptoKeyEngine::maker(unsigned int algorithm)
{
return new PKCS11DNSCryptoKeyEngine(algorithm);