/* Crypto stuff for Cutlass (C) 2004 Jack Lloyd Major TODOs: Catch all exceptions, convert to returns (C doesn't like exceptions) Key exchange (!) ? */ #include #include using namespace Botan; #include #include #include /* By defining our own local mutex type, we don't have to worry about whether or not Botan was built with a mutex module. Since we're already using pthreads in the rest of Cutlass, we don't have to worry about the portability of hardcoding using Pthreads (well...) */ class Cutlass_Mutex : public Mutex { public: void lock() { pthread_mutex_lock(&mutex); } void unlock() { pthread_mutex_unlock(&mutex); } Mutex* clone() const { return new Cutlass_Mutex; } Cutlass_Mutex() { pthread_mutex_init(&mutex, NULL); } ~Cutlass_Mutex() { pthread_mutex_destroy(&mutex); } private: pthread_mutex_t mutex; }; extern "C" { void cutlass_crypto_init() { try { Init::set_mutex_type(new Cutlass_Mutex); /* Don't pass the thread_safe flag, since we set a mutex explicitly before initializing the library. */ Init::initialize("use_engines"); /* In Botan 1.4.6, setting to 0 disables the failout, but in earlier versions this will cause private key loading to fail without ever trying, so we just set it to a largish value for now. */ Config::set("base/pkcs8_tries", "100"); } catch(std::exception& e) { fprintf(stderr, "Botan initalization failed (aborting): %s\n", e.what()); exit(1); } catch(...) { fprintf(stderr, "Botan initalization failed, unknown reason (aborting)\n"); exit(1); } } /* If it fails, don't abort, as we're quiting anyway */ void cutlass_crypto_shutdown() { try { Init::deinitialize(); } catch(std::exception& e) { fprintf(stderr, "Botan shutdown failed: %s\n", e.what()); } catch(...) { fprintf(stderr, "Botan shutdown failed, unknown reason\n"); } } /* Fingerprint a public key, by hashing it's plain DER representation with SHA-256 and then hex encoding that. */ char* fingerprint_key(cutlass_public_key keyobj) { uint8_t hash[CUT_ID_LEN]; fingerprint_key_bin(keyobj, hash); Pipe pipe(new Hex_Encoder); pipe.process_msg(hash, CUT_ID_LEN); std::string fprint = pipe.read_all_as_string(); char* retval = (char*)malloc(fprint.length()+1); if(!retval) return 0; memset(retval, 0, fprint.length()+1); strcpy(retval, fprint.c_str()); return retval; } /* Fingerprint a public key, by hashing it's plain DER representation with SHA-256, put it in the array */ void fingerprint_key_bin(cutlass_public_key keyobj, uint8_t hash[CUT_ID_LEN]) { X509_PublicKey* key = static_cast(keyobj.key); if(!key) { cutlass_sysmsg(NULL, CUT_ERROR, "fingerprint_key_bin: NULL argument (I hate you)\n"); return; } memset(hash, 0, CUT_ID_LEN); if(key) { Pipe pipe(new Hash_Filter("SHA-256")); pipe.start_msg(); X509::encode(*key, pipe, RAW_BER); pipe.end_msg(); pipe.read(hash, CUT_ID_LEN); } } static void delete_pipe(void* pipe_ptr) { if(!pipe_ptr) return; Pipe* pipe = static_cast(pipe_ptr); delete pipe; } void free_keyset(cutlass_keyset keyset) { delete_pipe(keyset.opaque_mac_send); delete_pipe(keyset.opaque_mac_recv); delete_pipe(keyset.opaque_cipher_send); delete_pipe(keyset.opaque_cipher_recv); delete_pipe(keyset.send_proc); delete_pipe(keyset.recv_proc); } cutlass_keyset empty_keyset() { cutlass_keyset result; result.opaque_cipher_filter_send = 0; result.opaque_cipher_filter_recv = 0; result.opaque_cipher_send = 0; result.opaque_cipher_recv = 0; result.opaque_mac_send = 0; result.opaque_mac_recv = 0; result.send_proc = new Pipe(new Cutlass_Kex_Writer); result.recv_proc = new Pipe(new Cutlass_Kex_Reader); return result; } void file_hash(int fd, uint8_t hash[CUT_CSUM_LEN]) { Pipe pipe(new Hash_Filter("SHA-256")); SecureVector buffer(4096); lseek(fd, 0, SEEK_SET); pipe.start_msg(); while(true) { ssize_t ret = ::read(fd, buffer, buffer.size()); if(ret == 0) break; if(ret == -1) cutlass_sysmsg(0, CUT_ERROR, "file_hash: File input fails\n"); pipe.write(buffer, ret); } pipe.end_msg(); if(pipe.remaining() == CUT_CSUM_LEN) pipe.read(hash, pipe.remaining()); else { cutlass_sysmsg(0, CUT_ERROR, "file_hash: Can't happen (but did)\n"); memset(hash, 0, sizeof(hash)); } } } /* extern "C" */