+struct crypt_rsa_privkey *crypt_rsa_generate_privkey(const int keysize) {
+ struct crypt_rsa_privkey *privkey = calloc(1, sizeof(*privkey));
+ int ret;
+
+ ret = gnutls_x509_privkey_init(&privkey->key);
+ if(ret < 0)
+ goto crypt_rsa_generate_privkey_fail;
+ privkey->free_key = 1;
+
+ ret = gnutls_x509_privkey_generate(privkey->key, GNUTLS_PK_RSA, keysize, 0);
+ if (ret < 0)
+ goto crypt_rsa_generate_privkey_fail;
+
+ ret = gnutls_privkey_init(&privkey->privkey);
+ if(ret < 0)
+ goto crypt_rsa_generate_privkey_fail;
+ privkey->free_privkey = 1;
+
+ ret = gnutls_privkey_import_x509(privkey->privkey, privkey->key, 0);
+ if(ret < 0)
+ goto crypt_rsa_generate_privkey_fail;
+
+ return privkey;
+ crypt_rsa_generate_privkey_fail:
+ crypt_rsa_unload_privkey(privkey);
+ return NULL;
+}
+
+char *crypt_rsa_export_privkey(struct crypt_rsa_privkey *privkey, int pubkey) {
+ size_t size = 1024;
+ char *buffer = malloc(size);
+ int ret;
+
+ if(pubkey) {
+ gnutls_pubkey_t pkey;
+ ret = gnutls_pubkey_init(&pkey);
+ if(ret < 0) {
+ free(buffer);
+ return NULL;
+ }
+ ret = gnutls_pubkey_import_privkey(pkey, privkey->privkey, GNUTLS_KEY_KEY_ENCIPHERMENT | GNUTLS_KEY_DIGITAL_SIGNATURE, 0);
+ if(ret < 0) {
+ free(buffer);
+ gnutls_pubkey_deinit(pkey);
+ return NULL;
+ }
+ ret = gnutls_pubkey_export(pkey, GNUTLS_X509_FMT_PEM, buffer, &size);
+ if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ buffer = realloc(buffer, size);
+ ret = gnutls_pubkey_export(pkey, GNUTLS_X509_FMT_PEM, buffer, &size);
+ }
+ gnutls_pubkey_deinit(pkey);
+ } else {
+ ret = gnutls_x509_privkey_export(privkey->key, GNUTLS_X509_FMT_PEM, buffer, &size);
+ if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ buffer = realloc(buffer, size);
+ ret = gnutls_x509_privkey_export(privkey->key, GNUTLS_X509_FMT_PEM, buffer, &size);
+ }
+ }
+ if(ret < 0) {
+ free(buffer);
+ return NULL;
+ }
+ return buffer;
+}
+
+void crypt_rsa_unload_privkey(struct crypt_rsa_privkey *privkey) {