/* Public/private key handling code (C) 2004,2005 Jack Lloyd */ #include #include #include using namespace Botan; #include #include namespace { /* Simply call the passphrase_func we're given when we need a passphrase */ class Cutlass_UI : public User_Interface { public: std::string get_passphrase(const std::string&, const std::string&, User_Interface::UI_Result&) const; Cutlass_UI(passphrase_func f) : get_pass(f) {} private: passphrase_func get_pass; }; std::string Cutlass_UI::get_passphrase(const std::string& /*object_type*/, const std::string& source_name, User_Interface::UI_Result& result) const { char buffer[128] = { 0 }; int f_result = get_pass(source_name.c_str(), buffer, sizeof(buffer)); result = User_Interface::CANCEL_ACTION; /* get_pass says user didn't cancel the action, etc */ if(f_result == 0) { result = User_Interface::OK; return std::string(buffer); } return ""; /* Ignored, as result is CANCEL_ACTION */ } } namespace { /* Just for debugging */ void handle_exception(const std::exception& e) { printf("EXCEPTION: %s\n", e.what()); } } extern "C" { cutlass_private_key load_private_key(const char* fsname, passphrase_func get_pass) { PKCS8_PrivateKey* privkey = 0; try { Cutlass_UI ui(get_pass); DataSource_Stream source(fsname); privkey = PKCS8::load_key(source, ui); } catch(std::exception& e) { handle_exception(e); } cutlass_private_key retval; retval.key = privkey; return retval; } void save_private_key(cutlass_private_key keyobj, const char* passphrase, FILE* out) { PKCS8_PrivateKey* pkcs8_priv = static_cast(keyobj.key); if(!pkcs8_priv) { cutlass_sysmsg(NULL, CUT_ERROR, "save_private_key: NULL argument (I hate you)\n"); return; } std::string encrypted_key; if(passphrase) encrypted_key = PKCS8::PEM_encode(*pkcs8_priv, passphrase); else encrypted_key = PKCS8::PEM_encode(*pkcs8_priv); fwrite(encrypted_key.c_str(), 1, encrypted_key.length(), out); } void save_public_key(cutlass_public_key keyobj, FILE* out) { X509_PublicKey* x509_pub = static_cast(keyobj.key); if(!x509_pub) { cutlass_sysmsg(NULL, CUT_ERROR, "save_public_key: NULL argument (I hate you)\n"); return; } std::string key = X509::PEM_encode(*x509_pub); fwrite(key.c_str(), 1, key.length(), out); } cutlass_public_key copy_public_key(cutlass_public_key keyobj) { X509_PublicKey* x509_pub = static_cast(keyobj.key); cutlass_public_key retval; retval.key = 0; if(!x509_pub) { cutlass_sysmsg(NULL, CUT_ERROR, "copy_public_key: NULL argument (I hate you)\n"); return retval; } retval.key = X509::copy_key(*x509_pub); return retval; } struct fake_callback_arg { callback_fn real_callback; void* real_callback_arg; }; static void fake_callback(UI::Pulse_Type, void* args) { fake_callback_arg* x = (fake_callback_arg*)args; if(x && x->real_callback) x->real_callback(x->real_callback_arg); } cutlass_private_key generate_rsa_key(uint32_t bitlength, callback_fn callback, void* callback_arg) { PKCS8_PrivateKey* rsa_key = 0; /* Nasty crap to translate Botan's callback system to the one we're using in Cutlass. */ fake_callback_arg fake_args; fake_args.real_callback = callback; fake_args.real_callback_arg = callback_arg; try { UI::set_pulse(fake_callback, &fake_args); rsa_key = new RSA_PrivateKey(bitlength); } catch(std::exception& e) { handle_exception(e); } UI::set_pulse(0, 0); /* clear out the pulse function */ cutlass_private_key retval; retval.key = rsa_key; return retval; } cutlass_private_key generate_dh_key(uint8_t group) { PKCS8_PrivateKey* dh_key = 0; try { std::string group_str = ""; if(group == DH_GROUP_1024) group_str = "IETF-1024"; if(group == DH_GROUP_2048) group_str = "IETF-2084"; if(group_str == "") throw Invalid_Argument("Unknown DH group ID " + to_string(group)); dh_key = new DH_PrivateKey(get_dl_group(group_str)); } catch(std::exception& e) { handle_exception(e); } cutlass_private_key retval; retval.key = dh_key; return retval; } void free_private_key(cutlass_private_key keyobj) { /* if keyobj.key is not a PKCS8_PrivateKey, we are fucked */ PKCS8_PrivateKey* pkcs8_priv = static_cast(keyobj.key); if(!pkcs8_priv) { cutlass_sysmsg(NULL, CUT_ERROR, "free_private_key: NULL argument (I hate you)\n"); return; } delete pkcs8_priv; } void free_public_key(cutlass_public_key keyobj) { X509_PublicKey* x509_pub = static_cast(keyobj.key); if(!x509_pub) { cutlass_sysmsg(NULL, CUT_ERROR, "free_public_key: NULL argument (I hate you)\n"); return; } delete x509_pub; } /* Create a new free-standing copy of the public portion of the key */ cutlass_public_key extract_public_key(cutlass_private_key keyobj) { try { PKCS8_PrivateKey* priv = static_cast(keyobj.key); if(!priv) { cutlass_sysmsg(NULL, CUT_ERROR, "extract_public_key: NULL argument (I hate you)\n"); cutlass_public_key retval; retval.key = 0; return retval; } /* Encode the public portion, then load it back in. We could just use copy_key here, that was only added in 1.4.0 tho. */ Pipe buffer; buffer.start_msg(); X509::encode(*priv, buffer); buffer.end_msg(); X509_PublicKey* pub = X509::load_key(buffer); cutlass_public_key retval; retval.key = pub; return retval; } catch(std::exception& e) { handle_exception(e); } cutlass_public_key retval; retval.key = 0; return retval; } }