X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilccrypt%2Fsilcpk.c;h=42aada1c1b7c2d7f6c9c6c924a4d74100c79d332;hb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;hp=7e7c234e72681cd6355c0e6b69aec9e51cf37215;hpb=35cdce343e56b7bae588a4fe7ba0bf8615a48170;p=silc.git diff --git a/lib/silccrypt/silcpk.c b/lib/silccrypt/silcpk.c index 7e7c234e..42aada1c 100644 --- a/lib/silccrypt/silcpk.c +++ b/lib/silccrypt/silcpk.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,6 @@ /* Generate new SILC key pair. */ SilcBool silc_pkcs_silc_generate_key(const char *algorithm, - const char *scheme, SilcUInt32 bits_key_len, const char *identifier, SilcRng rng, @@ -36,6 +35,7 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm, SilcSILCPrivateKey privkey; const SilcPKCSAlgorithm *alg; const SilcPKCSObject *pkcs; + SilcUInt32 version; SILC_LOG_DEBUG(("Generating SILC %s key pair with key length %d bits", algorithm, bits_key_len)); @@ -47,21 +47,28 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm, if (!pkcs) return FALSE; - alg = silc_pkcs_find_algorithm(algorithm, scheme); - if (!alg) - return FALSE; - /* Allocate SILC public key */ pubkey = silc_calloc(1, sizeof(*pubkey)); if (!pubkey) return FALSE; - pubkey->pkcs = alg; /* Decode identifier */ - if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier)) { + if (!silc_pkcs_silc_decode_identifier(identifier, &pubkey->identifier)) + return FALSE; + + if (pubkey->identifier.version && atoi(pubkey->identifier.version) >= 2) + version = 2; + else + version = 1; + + /* Allocate algorithm */ + alg = silc_pkcs_find_algorithm(algorithm, (version == 1 ? "pkcs1-no-oid" : + "pkcs1")); + if (!alg) { silc_free(pubkey); return FALSE; } + pubkey->pkcs = alg; /* Allocate SILC private key */ privkey = silc_calloc(1, sizeof(*privkey)); @@ -78,7 +85,8 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm, silc_free(privkey); return FALSE; } - (*ret_public_key)->pkcs = pkcs; + (*ret_public_key)->pkcs = (SilcPKCSObject *)pkcs; + (*ret_public_key)->alg = alg; (*ret_public_key)->public_key = pubkey; /* Allocate private key */ @@ -89,11 +97,12 @@ SilcBool silc_pkcs_silc_generate_key(const char *algorithm, silc_free(*ret_public_key); return FALSE; } - (*ret_private_key)->pkcs = pkcs; + (*ret_private_key)->pkcs = (SilcPKCSObject *)pkcs; + (*ret_private_key)->alg = alg; (*ret_private_key)->private_key = privkey; /* Generate the algorithm key pair */ - if (!alg->generate_key(bits_key_len, rng, &pubkey->public_key, + if (!alg->generate_key(alg, bits_key_len, rng, &pubkey->public_key, &privkey->private_key)) { silc_free(pubkey); silc_free(privkey); @@ -117,7 +126,7 @@ SilcBool silc_pkcs_silc_decode_identifier(const char *identifier, int len; /* Protocol says that at least UN and HN must be provided as identifier */ - if (!strstr(identifier, "UN=") && !strstr(identifier, "HN=")) { + if (!strstr(identifier, "UN=") || !strstr(identifier, "HN=")) { SILC_LOG_DEBUG(("The public does not have the required UN= and HN= " "identifiers")); return FALSE; @@ -169,6 +178,8 @@ SilcBool silc_pkcs_silc_decode_identifier(const char *identifier, ident->org = strdup(item + strcspn(cp, "=") + 1); else if (strstr(item, "C=")) ident->country = strdup(item + strcspn(cp, "=") + 1); + else if (strstr(item, "V=")) + ident->version = strdup(item + strcspn(cp, "=") + 1); cp += len; if (strlen(cp) < 1) @@ -187,108 +198,114 @@ SilcBool silc_pkcs_silc_decode_identifier(const char *identifier, arguments is NULL those are not encoded into the identifier string. Protocol says that at least username and host must be provided. */ -char *silc_pkcs_silc_encode_identifier(char *username, char *host, +char *silc_pkcs_silc_encode_identifier(SilcStack stack, + char *username, char *host, char *realname, char *email, - char *org, char *country) + char *org, char *country, + char *version) { - SilcBuffer buf; + SilcBufferStruct buf; char *identifier; - SilcUInt32 len, tlen = 0; - if (!username || !host) + if (!username || !host) { + SILC_LOG_ERROR(("Public key identifier is missing UN and/or HN")); return NULL; - - len = (username ? strlen(username) : 0) + - (host ? strlen(host) : 0) + - (realname ? strlen(realname) : 0) + - (email ? strlen(email) : 0) + - (org ? strlen(org) : 0) + - (country ? strlen(country) : 0); - - if (len < 3) + } + if (strlen(username) < 1 || strlen(host) < 1) return NULL; - len += 3 + 5 + 5 + 4 + 4 + 4; - buf = silc_buffer_alloc(len); - if (!buf) - return NULL; - silc_buffer_pull_tail(buf, len); - - if (username) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING("UN="), - SILC_STR_UI32_STRING(username), - SILC_STR_END); - silc_buffer_pull(buf, 3 + strlen(username)); - tlen = 3 + strlen(username); + memset(&buf, 0, sizeof(buf)); + + if (username) + silc_buffer_sformat(stack, &buf, + SILC_STR_ADVANCE, + SILC_STR_UI32_STRING("UN="), + SILC_STR_UI32_STRING(username), + SILC_STR_END); + + if (host) + silc_buffer_sformat(stack, &buf, + SILC_STR_ADVANCE, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("HN="), + SILC_STR_UI32_STRING(host), + SILC_STR_END); + + if (realname) + silc_buffer_sformat(stack, &buf, + SILC_STR_ADVANCE, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("RN="), + SILC_STR_UI32_STRING(realname), + SILC_STR_END); + + if (email) + silc_buffer_sformat(stack, &buf, + SILC_STR_ADVANCE, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("E="), + SILC_STR_UI32_STRING(email), + SILC_STR_END); + + if (org) + silc_buffer_sformat(stack, &buf, + SILC_STR_ADVANCE, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("O="), + SILC_STR_UI32_STRING(org), + SILC_STR_END); + + if (country) + silc_buffer_sformat(stack, &buf, + SILC_STR_ADVANCE, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("C="), + SILC_STR_UI32_STRING(country), + SILC_STR_END); + + if (version) { + if (strlen(version) > 1 || !isdigit(version[0])) { + silc_buffer_spurge(stack, &buf); + SILC_LOG_ERROR(("Public key identifier has invalid version (V)")); + return NULL; + } + silc_buffer_sformat(stack, &buf, + SILC_STR_ADVANCE, + SILC_STR_UI32_STRING(", "), + SILC_STR_UI32_STRING("V="), + SILC_STR_UI32_STRING(version), + SILC_STR_END); } - if (host) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("HN="), - SILC_STR_UI32_STRING(host), - SILC_STR_END); - silc_buffer_pull(buf, 5 + strlen(host)); - tlen += 5 + strlen(host); - } + silc_buffer_sformat(stack, &buf, SILC_STR_UI_CHAR(0), SILC_STR_END); - if (realname) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("RN="), - SILC_STR_UI32_STRING(realname), - SILC_STR_END); - silc_buffer_pull(buf, 5 + strlen(realname)); - tlen += 5 + strlen(realname); - } + identifier = silc_buffer_steal(&buf, NULL); + return identifier; +} - if (email) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("E="), - SILC_STR_UI32_STRING(email), - SILC_STR_END); - silc_buffer_pull(buf, 4 + strlen(email)); - tlen += 4 + strlen(email); - } +/* Return SILC public key version */ - if (org) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("O="), - SILC_STR_UI32_STRING(org), - SILC_STR_END); - silc_buffer_pull(buf, 4 + strlen(org)); - tlen += 4 + strlen(org); - } +int silc_pkcs_silc_public_key_version(SilcPublicKey public_key) +{ + SilcSILCPublicKey silc_pubkey; - if (country) { - silc_buffer_format(buf, - SILC_STR_UI32_STRING(", "), - SILC_STR_UI32_STRING("C="), - SILC_STR_UI32_STRING(country), - SILC_STR_END); - silc_buffer_pull(buf, 4 + strlen(country)); - tlen += 4 + strlen(country); - } + if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC) + return -1; - silc_buffer_push(buf, buf->data - buf->head); - identifier = silc_calloc(tlen + 1, sizeof(*identifier)); - if (!identifier) - return NULL; - memcpy(identifier, buf->data, tlen); - silc_buffer_free(buf); + silc_pubkey = public_key->public_key; - return identifier; -} + /* If version identifire is not present it is version 1. */ + if (!silc_pubkey->identifier.version) + return 1; + return atoi(silc_pubkey->identifier.version); +} /*************************** Public key routines *****************************/ /* Returns PKCS algorithm context */ -const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key) +SILC_PKCS_GET_ALGORITHM(silc_pkcs_silc_get_algorithm) { SilcSILCPublicKey silc_pubkey = public_key; return silc_pubkey->pkcs; @@ -296,14 +313,11 @@ const SilcPKCSAlgorithm *silc_pkcs_silc_get_algorithm(void *public_key) /* Imports SILC protocol style public key from SILC public key file */ -SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata, - SilcUInt32 filedata_len, - SilcPKCSFileEncoding encoding, - void **ret_public_key) +SILC_PKCS_IMPORT_PUBLIC_KEY_FILE(silc_pkcs_silc_import_public_key_file) { SilcUInt32 i, len; unsigned char *data = NULL; - SilcBool ret; + int ret; SILC_LOG_DEBUG(("Parsing SILC public key file")); @@ -312,11 +326,15 @@ SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata, /* Check start of file and remove header from the data. */ len = strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN); - if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) + if (filedata_len < len + strlen(SILC_PKCS_PUBLIC_KEYFILE_END)) { + SILC_LOG_DEBUG(("Malformed SILC public key header")); return FALSE; + } for (i = 0; i < len; i++) { - if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) + if (*filedata != SILC_PKCS_PUBLIC_KEYFILE_BEGIN[i]) { + SILC_LOG_DEBUG(("Malformed SILC public key header")); return FALSE; + } filedata++; } filedata_len -= (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) + @@ -327,27 +345,24 @@ SilcBool silc_pkcs_silc_import_public_key_file(unsigned char *filedata, break; case SILC_PKCS_FILE_BASE64: - data = silc_pem_decode(filedata, filedata_len, &filedata_len); + data = silc_base64_decode(NULL, filedata, filedata_len, &filedata_len); if (!data) return FALSE; filedata = data; break; } - ret = silc_pkcs_silc_import_public_key(filedata, filedata_len, - ret_public_key); + ret = silc_pkcs_silc_import_public_key(pkcs, NULL, filedata, filedata_len, + ret_public_key, ret_alg); silc_free(data); - return ret; + return ret ? TRUE : FALSE; } /* Imports SILC protocol style public key */ -SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, - SilcUInt32 key_len, - void **ret_public_key) +SILC_PKCS_IMPORT_PUBLIC_KEY(silc_pkcs_silc_import_public_key) { - const SilcPKCSAlgorithm *pkcs; SilcBufferStruct buf, alg_key; SilcSILCPublicKey silc_pubkey = NULL; SilcAsn1 asn1 = NULL; @@ -359,12 +374,13 @@ SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, SILC_LOG_DEBUG(("Parsing SILC public key")); if (!ret_public_key) - return FALSE; + return 0; silc_buffer_set(&buf, key, key_len); /* Get length */ ret = silc_buffer_unformat(&buf, + SILC_STR_ADVANCE, SILC_STR_UI_INT(&totlen), SILC_STR_END); if (ret == -1) @@ -380,7 +396,7 @@ SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, /* Get algorithm name and identifier */ ret = silc_buffer_unformat(&buf, - SILC_STR_OFFSET(4), + SILC_STR_ADVANCE, SILC_STR_UI16_NSTRING_ALLOC(&pkcs_name, &pkcs_len), SILC_STR_UI16_NSTRING_ALLOC(&ident, &identifier_len), SILC_STR_END); @@ -392,11 +408,9 @@ SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, goto err; /* Get key data */ - silc_buffer_pull(&buf, 4 + 2 + pkcs_len + 2 + identifier_len); keydata_len = silc_buffer_len(&buf); ret = silc_buffer_unformat(&buf, - SILC_STR_UI_XNSTRING(&key_data, - keydata_len), + SILC_STR_DATA(&key_data, keydata_len), SILC_STR_END); if (ret == -1) goto err; @@ -410,22 +424,34 @@ SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, if (!silc_pkcs_silc_decode_identifier(ident, &silc_pubkey->identifier)) goto err; - asn1 = silc_asn1_alloc(); + asn1 = silc_asn1_alloc(NULL); if (!asn1) goto err; + SILC_LOG_DEBUG(("Public key version %s", + (!silc_pubkey->identifier.version ? "1" : + silc_pubkey->identifier.version))); + if (!strcmp(pkcs_name, "rsa")) { /* Parse the SILC RSA public key */ SilcUInt32 e_len, n_len; SilcMPInt n, e; - /* Get PKCS object */ - pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid"); - if (!pkcs) { - SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + /* Get PKCS object. Different PKCS #1 scheme is used with different + versions. */ + if (!silc_pubkey->identifier.version || + atoi(silc_pubkey->identifier.version) <= 1) { + /* Version 1 */ + alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid"); + } else { + /* Version 2 and newer */ + alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1"); + } + if (!alg) { + SILC_LOG_DEBUG(("Unsupported PKCS algorithm: rsa")); goto err; } - silc_pubkey->pkcs = pkcs; + silc_pubkey->pkcs = alg; if (keydata_len < 4) goto err; @@ -471,18 +497,18 @@ SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, } /* Import PKCS algorithm public key */ - if (pkcs->import_public_key) - if (!pkcs->import_public_key(alg_key.data, silc_buffer_len(&alg_key), - &silc_pubkey->public_key)) - goto err; + if (!alg->import_public_key(alg, alg_key.data, silc_buffer_len(&alg_key), + &silc_pubkey->public_key)) + goto err; silc_free(pkcs_name); silc_free(ident); silc_asn1_free(asn1); *ret_public_key = silc_pubkey; + *ret_alg = alg; - return TRUE; + return key_len; err: silc_free(pkcs_name); @@ -490,15 +516,12 @@ SilcBool silc_pkcs_silc_import_public_key(unsigned char *key, silc_free(silc_pubkey); if (asn1) silc_asn1_free(asn1); - return FALSE; + return 0; } /* Exports public key as SILC protocol style public key file */ -unsigned char * -silc_pkcs_silc_export_public_key_file(void *public_key, - SilcPKCSFileEncoding encoding, - SilcUInt32 *ret_len) +SILC_PKCS_EXPORT_PUBLIC_KEY_FILE(silc_pkcs_silc_export_public_key_file) { SilcBuffer buf; unsigned char *key, *data; @@ -507,7 +530,7 @@ silc_pkcs_silc_export_public_key_file(void *public_key, SILC_LOG_DEBUG(("Encoding SILC public key file")); /* Export key */ - key = silc_pkcs_silc_export_public_key(public_key, &key_len); + key = silc_pkcs_silc_export_public_key(pkcs, stack, public_key, &key_len); if (!key) return NULL; @@ -516,48 +539,47 @@ silc_pkcs_silc_export_public_key_file(void *public_key, break; case SILC_PKCS_FILE_BASE64: - data = silc_pem_encode_file(key, key_len); + data = silc_base64_encode_file(stack, key, key_len); if (!data) return NULL; - silc_free(key); + silc_sfree(stack, key); key = data; key_len = strlen(data); break; } /* Encode SILC public key file */ - buf = silc_buffer_alloc_size(key_len + - (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) + - strlen(SILC_PKCS_PUBLIC_KEYFILE_END))); + buf = silc_buffer_salloc_size(stack, key_len + + (strlen(SILC_PKCS_PUBLIC_KEYFILE_BEGIN) + + strlen(SILC_PKCS_PUBLIC_KEYFILE_END))); if (!buf) { - silc_free(key); + silc_sfree(stack, key); return NULL; } - if (silc_buffer_format(buf, - SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN), - SILC_STR_UI_XNSTRING(key, key_len), - SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END), - SILC_STR_END) < 0) { - silc_buffer_free(buf); - silc_free(key); + if (silc_buffer_sformat(stack, buf, + SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_BEGIN), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_UI32_STRING(SILC_PKCS_PUBLIC_KEYFILE_END), + SILC_STR_END) < 0) { + silc_buffer_sfree(stack, buf); + silc_sfree(stack, key); return NULL; } - silc_free(key); + silc_sfree(stack, key); key = silc_buffer_steal(buf, ret_len); - silc_buffer_free(buf); + silc_buffer_sfree(stack, buf); return key; } /* Exports public key as SILC protocol style public key */ -unsigned char *silc_pkcs_silc_export_public_key(void *public_key, - SilcUInt32 *ret_len) +SILC_PKCS_EXPORT_PUBLIC_KEY(silc_pkcs_silc_export_public_key) { SilcSILCPublicKey silc_pubkey = public_key; - const SilcPKCSAlgorithm *pkcs = silc_pubkey->pkcs; + const SilcPKCSAlgorithm *alg = silc_pubkey->pkcs; SilcBufferStruct alg_key; SilcBuffer buf = NULL; SilcAsn1 asn1 = NULL; @@ -568,28 +590,34 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key, SILC_LOG_DEBUG(("Encoding SILC public key")); /* Export PKCS algorithm public key */ - if (pkcs->export_public_key) - pk = pkcs->export_public_key(silc_pubkey->public_key, &pk_len); - if (!pk) + if (alg->export_public_key) + pk = alg->export_public_key(alg, stack, silc_pubkey->public_key, &pk_len); + if (!pk) { + SILC_LOG_ERROR(("Error exporting PKCS algorithm key")); return NULL; + } silc_buffer_set(&alg_key, pk, pk_len); /* Encode identifier */ identifier = - silc_pkcs_silc_encode_identifier(silc_pubkey->identifier.username, + silc_pkcs_silc_encode_identifier(stack, + silc_pubkey->identifier.username, silc_pubkey->identifier.host, silc_pubkey->identifier.realname, silc_pubkey->identifier.email, silc_pubkey->identifier.org, - silc_pubkey->identifier.country); - if (!identifier) + silc_pubkey->identifier.country, + silc_pubkey->identifier.version); + if (!identifier) { + SILC_LOG_ERROR(("Error encoding SILC public key identifier")); goto err; + } - asn1 = silc_asn1_alloc(); + asn1 = silc_asn1_alloc(stack); if (!asn1) goto err; - if (!strcmp(pkcs->name, "rsa")) { + if (!strcmp(alg->name, "rsa")) { /* Parse the PKCS #1 public key */ SilcMPInt n, e; SilcUInt32 n_len, e_len; @@ -612,7 +640,7 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key, if (!nb) goto err; key_len = e_len + 4 + n_len + 4; - key = silc_calloc(key_len, sizeof(*key)); + key = silc_scalloc(stack, key_len, sizeof(*key)); if (!key) goto err; @@ -627,44 +655,44 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key, silc_free(nb); silc_free(eb); - } else if (!strcmp(pkcs->name, "dsa")) { + } else if (!strcmp(alg->name, "dsa")) { SILC_NOT_IMPLEMENTED("SILC DSA Public Key"); goto err; } else { - SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + SILC_LOG_ERROR(("Unsupported PKCS algorithm: %s", alg->name)); goto err; } /* Encode SILC Public Key */ - totlen = 2 + strlen(pkcs->name) + 2 + strlen(identifier) + key_len; - buf = silc_buffer_alloc_size(totlen + 4); + totlen = 2 + strlen(alg->name) + 2 + strlen(identifier) + key_len; + buf = silc_buffer_salloc_size(stack, totlen + 4); if (!buf) goto err; - if (silc_buffer_format(buf, - SILC_STR_UI_INT(totlen), - SILC_STR_UI_SHORT(strlen(pkcs->name)), - SILC_STR_UI32_STRING(pkcs->name), - SILC_STR_UI_SHORT(strlen(identifier)), - SILC_STR_UI32_STRING(identifier), - SILC_STR_UI_XNSTRING(key, key_len), - SILC_STR_END) < 0) + if (silc_buffer_sformat(stack, buf, + SILC_STR_UI_INT(totlen), + SILC_STR_UI_SHORT(strlen(alg->name)), + SILC_STR_UI32_STRING(alg->name), + SILC_STR_UI_SHORT(strlen(identifier)), + SILC_STR_UI32_STRING(identifier), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_END) < 0) goto err; ret = silc_buffer_steal(buf, ret_len); - silc_buffer_free(buf); - silc_free(key); - silc_free(identifier); + silc_buffer_sfree(stack, buf); + silc_sfree(stack, key); + silc_sfree(stack, identifier); + silc_buffer_spurge(stack, &alg_key); silc_asn1_free(asn1); return ret; err: - silc_free(identifier); - silc_free(pk); - silc_free(key); - if (buf) - silc_buffer_free(buf); + silc_sfree(stack, identifier); + silc_sfree(stack, pk); + silc_sfree(stack, key); + silc_buffer_sfree(stack, buf); if (asn1) silc_asn1_free(asn1); return NULL; @@ -672,17 +700,19 @@ unsigned char *silc_pkcs_silc_export_public_key(void *public_key, /* Return key length */ -SilcUInt32 silc_pkcs_silc_public_key_bitlen(void *public_key) +SILC_PKCS_PUBLIC_KEY_BITLEN(silc_pkcs_silc_public_key_bitlen) { SilcSILCPublicKey silc_pubkey = public_key; - return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->public_key); + return silc_pubkey->pkcs->public_key_bitlen(silc_pubkey->pkcs, + silc_pubkey->public_key); } /* Copy public key */ -void *silc_pkcs_silc_public_key_copy(void *public_key) +SILC_PKCS_PUBLIC_KEY_COPY(silc_pkcs_silc_public_key_copy) { SilcSILCPublicKey silc_pubkey = public_key, new_pubkey; + SilcPublicKeyIdentifier ident = &silc_pubkey->identifier; new_pubkey = silc_calloc(1, sizeof(*new_pubkey)); if (!new_pubkey) @@ -690,18 +720,41 @@ void *silc_pkcs_silc_public_key_copy(void *public_key) new_pubkey->pkcs = silc_pubkey->pkcs; new_pubkey->public_key = - silc_pubkey->pkcs->public_key_copy(silc_pubkey->public_key); + silc_pubkey->pkcs->public_key_copy(silc_pubkey->pkcs, + silc_pubkey->public_key); if (!new_pubkey->public_key) { silc_free(new_pubkey); return NULL; } + if (ident->username) + new_pubkey->identifier.username = + silc_memdup(ident->username, strlen(ident->username)); + if (ident->host) + new_pubkey->identifier.host = + silc_memdup(ident->host, strlen(ident->host)); + if (ident->realname) + new_pubkey->identifier.realname = + silc_memdup(ident->realname, strlen(ident->realname)); + if (ident->email) + new_pubkey->identifier.email = + silc_memdup(ident->email, strlen(ident->email)); + if (ident->org) + new_pubkey->identifier.org = + silc_memdup(ident->org, strlen(ident->org)); + if (ident->country) + new_pubkey->identifier.country = + silc_memdup(ident->country, strlen(ident->country)); + if (ident->version) + new_pubkey->identifier.version = + silc_memdup(ident->version, strlen(ident->version)); + return new_pubkey; } /* Compares public keys */ -SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2) +SILC_PKCS_PUBLIC_KEY_COMPARE(silc_pkcs_silc_public_key_compare) { SilcSILCPublicKey k1 = key1, k2 = key2; @@ -744,16 +797,23 @@ SilcBool silc_pkcs_silc_public_key_compare(void *key1, void *key2) strcmp(k1->identifier.country, k2->identifier.country))) return FALSE; - return k1->pkcs->public_key_compare(k1->public_key, k2->public_key); + if ((k1->identifier.version && !k2->identifier.version) || + (!k1->identifier.version && k2->identifier.version) || + (k1->identifier.version && k2->identifier.version && + strcmp(k1->identifier.version, k2->identifier.version))) + return FALSE; + + return k1->pkcs->public_key_compare(k1->pkcs, k1->public_key, k2->public_key); } /* Frees public key */ -void silc_pkcs_silc_public_key_free(void *public_key) +SILC_PKCS_PUBLIC_KEY_FREE(silc_pkcs_silc_public_key_free) { SilcSILCPublicKey silc_pubkey = public_key; - silc_pubkey->pkcs->public_key_free(silc_pubkey->public_key); + silc_pubkey->pkcs->public_key_free(silc_pubkey->pkcs, + silc_pubkey->public_key); silc_free(silc_pubkey->identifier.username); silc_free(silc_pubkey->identifier.host); @@ -761,6 +821,7 @@ void silc_pkcs_silc_public_key_free(void *public_key) silc_free(silc_pubkey->identifier.email); silc_free(silc_pubkey->identifier.org); silc_free(silc_pubkey->identifier.country); + silc_free(silc_pubkey->identifier.version); silc_free(silc_pubkey); } @@ -772,12 +833,7 @@ void silc_pkcs_silc_public_key_free(void *public_key) /* Imports SILC implementation style private key file */ -SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata, - SilcUInt32 filedata_len, - const char *passphrase, - SilcUInt32 passphrase_len, - SilcPKCSFileEncoding encoding, - void **ret_private_key) +SILC_PKCS_IMPORT_PRIVATE_KEY_FILE(silc_pkcs_silc_import_private_key_file) { SilcCipher aes; SilcHash sha1; @@ -785,17 +841,21 @@ SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata, SilcUInt32 blocklen; unsigned char tmp[32], keymat[64], *data = NULL; SilcUInt32 i, len, magic, mac_len; - SilcBool ret; + int ret; SILC_LOG_DEBUG(("Parsing SILC private key file")); /* Check start of file and remove header from the data. */ len = strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN); - if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) + if (filedata_len < len + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)) { + SILC_LOG_DEBUG(("Malformed SILC private key header")); return FALSE; + } for (i = 0; i < len; i++) { - if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) + if (*filedata != SILC_PKCS_PRIVATE_KEYFILE_BEGIN[i]) { + SILC_LOG_DEBUG(("Malformed SILC private key header")); return FALSE; + } filedata++; } @@ -807,7 +867,7 @@ SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata, break; case SILC_PKCS_FILE_BASE64: - data = silc_pem_decode(filedata, filedata_len, &len); + data = silc_base64_decode(NULL, filedata, filedata_len, &len); if (!data) return FALSE; filedata = data; @@ -905,24 +965,23 @@ SilcBool silc_pkcs_silc_import_private_key_file(unsigned char *filedata, silc_cipher_free(aes); /* Import the private key */ - ret = silc_pkcs_silc_import_private_key(filedata, len, ret_private_key); + ret = silc_pkcs_silc_import_private_key(pkcs, NULL, filedata, + len, ret_private_key, ret_alg); silc_free(data); - return ret; + return ret ? TRUE : FALSE; } /* Private key version */ #define SILC_PRIVATE_KEY_VERSION_1 0x82171273 +#define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1 /* Imports SILC implementation style private key */ -SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, - SilcUInt32 key_len, - void **ret_private_key) +SILC_PKCS_IMPORT_PRIVATE_KEY(silc_pkcs_silc_import_private_key) { SilcBufferStruct buf; - const SilcPKCSAlgorithm *pkcs; SilcBufferStruct alg_key; SilcSILCPrivateKey silc_privkey = NULL; SilcAsn1 asn1 = NULL; @@ -934,9 +993,9 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, SILC_LOG_DEBUG(("Parsing SILC private key")); if (!ret_private_key) - return FALSE; + return 0; - silc_buffer_set(&buf, key, key_len); + silc_buffer_set(&buf, (unsigned char *)key, key_len); /* Get algorithm name and identifier */ ret = @@ -967,7 +1026,7 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, if (!silc_privkey) goto err; - asn1 = silc_asn1_alloc(); + asn1 = silc_asn1_alloc(NULL); if (!asn1) goto err; @@ -978,17 +1037,8 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, unsigned char *tmp; SilcUInt32 len, ver; - /* Get PKCS object */ - pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid"); - if (!pkcs) { - SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); - goto err; - } - silc_privkey->pkcs = pkcs; - if (keydata_len < 4) goto err; - silc_buffer_set(&k, key_data, keydata_len); /* Get version. Key without the version is old style private key @@ -999,8 +1049,10 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, goto err; silc_buffer_pull(&k, 4); - if (ver != SILC_PRIVATE_KEY_VERSION_1) { + if (ver != SILC_PRIVATE_KEY_VERSION_1 && + ver != SILC_PRIVATE_KEY_VERSION_2) { len = ver; + ver = 0; } else { if (silc_buffer_unformat(&k, SILC_STR_UI_INT(&len), @@ -1009,9 +1061,28 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, silc_buffer_pull(&k, 4); } + /* Get PKCS object. Different PKCS #1 scheme is used with different + versions. */ + if (ver == 0 || ver == SILC_PRIVATE_KEY_VERSION_1) { + /* Version 0 and 1 */ + alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid"); + } else { + /* Version 2 and newer */ + alg = silc_pkcs_find_algorithm(pkcs_name, "pkcs1"); + } + if (!alg) { + SILC_LOG_DEBUG(("Unsupported PKCS algorithm")); + goto err; + } + silc_privkey->pkcs = alg; + + SILC_LOG_DEBUG(("Private key version %s", + (ver == SILC_PRIVATE_KEY_VERSION_1 ? "1" : + ver == SILC_PRIVATE_KEY_VERSION_2 ? "2" : "0"))); + /* Get e */ if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_DATA(&tmp, len), SILC_STR_END) < 0) goto err; silc_mp_init(&e); @@ -1025,7 +1096,7 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, goto err; silc_buffer_pull(&k, 4); if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_DATA(&tmp, len), SILC_STR_END) < 0) goto err; silc_mp_init(&n); @@ -1039,7 +1110,7 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, goto err; silc_buffer_pull(&k, 4); if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_DATA(&tmp, len), SILC_STR_END) < 0) goto err; silc_mp_init(&d); @@ -1053,7 +1124,7 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, goto err; silc_buffer_pull(&k, 4); if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_DATA(&tmp, len), SILC_STR_END) < 0) goto err; silc_mp_init(&dp); @@ -1067,14 +1138,14 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, goto err; silc_buffer_pull(&k, 4); if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_DATA(&tmp, len), SILC_STR_END) < 0) goto err; silc_mp_init(&dq); silc_mp_bin2mp(tmp, len, &dq); silc_buffer_pull(&k, len); - if (ver != SILC_PRIVATE_KEY_VERSION_1) { + if (ver == 0) { /* Old version */ /* Get pQ len */ @@ -1106,7 +1177,7 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, goto err; silc_buffer_pull(&k, 4); if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_DATA(&tmp, len), SILC_STR_END) < 0) goto err; silc_mp_init(&qp); @@ -1121,7 +1192,7 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, goto err; silc_buffer_pull(&k, 4); if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_DATA(&tmp, len), SILC_STR_END) < 0) goto err; silc_mp_init(&p); @@ -1135,14 +1206,14 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, goto err; silc_buffer_pull(&k, 4); if (silc_buffer_unformat(&k, - SILC_STR_UI_XNSTRING(&tmp, len), + SILC_STR_DATA(&tmp, len), SILC_STR_END) < 0) goto err; silc_mp_init(&q); silc_mp_bin2mp(tmp, len, &q); silc_buffer_pull(&k, len); - if (ver != SILC_PRIVATE_KEY_VERSION_1) { + if (ver == 0) { /* Old version. Compute to new version */ SILC_LOG_DEBUG(("Old version private key")); silc_mp_init(&qp); @@ -1185,35 +1256,30 @@ SilcBool silc_pkcs_silc_import_private_key(unsigned char *key, } /* Import PKCS algorithm private key */ - if (pkcs->import_private_key) - if (!pkcs->import_private_key(alg_key.data, silc_buffer_len(&alg_key), - &silc_privkey->private_key)) - goto err; + if (!alg->import_private_key(alg, alg_key.data, silc_buffer_len(&alg_key), + &silc_privkey->private_key)) + goto err; silc_free(pkcs_name); silc_asn1_free(asn1); *ret_private_key = silc_privkey; + *ret_alg = alg; - return TRUE; + return key_len; err: silc_free(pkcs_name); silc_free(silc_privkey); if (asn1) silc_asn1_free(asn1); - return FALSE; + SILC_LOG_ERROR(("Malformed SILC private key ")); + return 0; } /* Exports private key as SILC implementation style private key file */ -unsigned char * -silc_pkcs_silc_export_private_key_file(void *private_key, - const char *passphrase, - SilcUInt32 passphrase_len, - SilcPKCSFileEncoding encoding, - SilcRng rng, - SilcUInt32 *ret_len) +SILC_PKCS_EXPORT_PRIVATE_KEY_FILE(silc_pkcs_silc_export_private_key_file) { SilcCipher aes; SilcHash sha1; @@ -1227,7 +1293,7 @@ silc_pkcs_silc_export_private_key_file(void *private_key, SILC_LOG_DEBUG(("Encoding SILC private key file")); /* Export the private key */ - key = silc_pkcs_silc_export_private_key(private_key, &key_len); + key = silc_pkcs_silc_export_private_key(pkcs, stack, private_key, &key_len); if (!key) return NULL; @@ -1237,19 +1303,20 @@ silc_pkcs_silc_export_private_key_file(void *private_key, /* Allocate the AES cipher */ if (!silc_cipher_alloc("aes-256-cbc", &aes)) { SILC_LOG_ERROR(("Could not allocate AES cipher, probably not registered")); - silc_free(key); + silc_sfree(stack, key); return NULL; } blocklen = silc_cipher_get_block_len(aes); if (blocklen * 2 > sizeof(tmp)) { silc_cipher_free(aes); - silc_free(key); + silc_sfree(stack, key); return NULL; } /* Allocate SHA1 hash */ if (!silc_hash_alloc("sha1", &sha1)) { SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered")); + silc_sfree(stack, key); silc_cipher_free(aes); return NULL; } @@ -1257,6 +1324,7 @@ silc_pkcs_silc_export_private_key_file(void *private_key, /* Allocate HMAC */ if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) { SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered")); + silc_sfree(stack, key); silc_hash_free(sha1); silc_cipher_free(aes); return NULL; @@ -1283,8 +1351,9 @@ silc_pkcs_silc_export_private_key_file(void *private_key, /* Allocate buffer for encryption */ len = silc_hmac_len(sha1hmac); padlen = 16 + (16 - ((key_len + 4) % blocklen)); - enc = silc_buffer_alloc_size(4 + 4 + key_len + padlen + len); + enc = silc_buffer_salloc_size(stack, 4 + 4 + key_len + padlen + len); if (!enc) { + silc_sfree(stack, key); silc_hmac_free(sha1hmac); silc_hash_free(sha1); silc_cipher_free(aes); @@ -1300,12 +1369,12 @@ silc_pkcs_silc_export_private_key_file(void *private_key, silc_buffer_pull(enc, 4); /* Encode the buffer */ - silc_buffer_format(enc, - SILC_STR_UI_INT(key_len), - SILC_STR_UI_XNSTRING(key, key_len), - SILC_STR_UI_XNSTRING(tmp, padlen), - SILC_STR_END); - silc_free(key); + silc_buffer_sformat(stack, enc, + SILC_STR_UI_INT(key_len), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_UI_XNSTRING(tmp, padlen), + SILC_STR_END); + silc_sfree(stack, key); /* Encrypt. */ silc_cipher_encrypt(aes, enc->data, enc->data, silc_buffer_len(enc) - len, @@ -1334,13 +1403,13 @@ silc_pkcs_silc_export_private_key_file(void *private_key, break; case SILC_PKCS_FILE_BASE64: - data = silc_pem_encode_file(enc->data, silc_buffer_len(enc)); + data = silc_base64_encode_file(stack, enc->data, silc_buffer_len(enc)); if (!data) { silc_buffer_clear(enc); - silc_buffer_free(enc); + silc_buffer_sfree(stack, enc); return NULL; } - silc_free(silc_buffer_steal(enc, NULL)); + silc_sfree(stack, silc_buffer_steal(enc, NULL)); silc_buffer_set(enc, data, strlen(data)); break; } @@ -1351,31 +1420,30 @@ silc_pkcs_silc_export_private_key_file(void *private_key, /* Encode the data and save to file */ len = key_len + (strlen(SILC_PKCS_PRIVATE_KEYFILE_BEGIN) + strlen(SILC_PKCS_PRIVATE_KEYFILE_END)); - buf = silc_buffer_alloc_size(len); + buf = silc_buffer_salloc_size(stack, len); if (!buf) { - silc_buffer_free(enc); + silc_buffer_sfree(stack, enc); return NULL; } - silc_buffer_format(buf, - SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN), - SILC_STR_UI_XNSTRING(key, key_len), - SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END), - SILC_STR_END); + silc_buffer_sformat(stack, buf, + SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_BEGIN), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_UI32_STRING(SILC_PKCS_PRIVATE_KEYFILE_END), + SILC_STR_END); - silc_buffer_free(enc); + silc_buffer_sfree(stack, enc); data = silc_buffer_steal(buf, ret_len); - silc_buffer_free(buf); + silc_buffer_sfree(stack, buf); return data; } /* Exports private key as SILC implementation style private key */ -unsigned char *silc_pkcs_silc_export_private_key(void *private_key, - SilcUInt32 *ret_len) +SILC_PKCS_EXPORT_PRIVATE_KEY(silc_pkcs_silc_export_private_key) { SilcSILCPrivateKey silc_privkey = private_key; - const SilcPKCSAlgorithm *pkcs = silc_privkey->pkcs; + const SilcPKCSAlgorithm *alg = silc_privkey->pkcs; SilcBufferStruct alg_key; SilcBuffer buf = NULL; SilcAsn1 asn1 = NULL; @@ -1385,17 +1453,18 @@ unsigned char *silc_pkcs_silc_export_private_key(void *private_key, SILC_LOG_DEBUG(("Encoding SILC private key")); /* Export PKCS algorithm private key */ - if (pkcs->export_private_key) - prv = pkcs->export_private_key(silc_privkey->private_key, &prv_len); + if (alg->export_private_key) + prv = alg->export_private_key(alg, stack, + silc_privkey->private_key, &prv_len); if (!prv) return NULL; silc_buffer_set(&alg_key, prv, prv_len); - asn1 = silc_asn1_alloc(); + asn1 = silc_asn1_alloc(stack); if (!asn1) goto err; - if (!strcmp(pkcs->name, "rsa")) { + if (!strcmp(alg->name, "rsa")) { /* Parse the PKCS #1 private key */ SilcMPInt n, e, d, dp, dq, qp, p, q; SilcUInt32 e_len, n_len, d_len, dp_len, dq_len, @@ -1428,32 +1497,32 @@ unsigned char *silc_pkcs_silc_export_private_key(void *private_key, len = 4 + e_len + 4 + n_len + 4 + d_len + 4+ dp_len + 4 + dq_len + 4 + qp_len + 4 + p_len + 4 + q_len + 4; - buf = silc_buffer_alloc_size(len); + buf = silc_buffer_salloc_size(stack, len); if (!buf) goto err; - if (silc_buffer_format(buf, - SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1), - SILC_STR_UI_INT(e_len), - SILC_STR_UI_XNSTRING(eb, e_len), - SILC_STR_UI_INT(n_len), - SILC_STR_UI_XNSTRING(nb, n_len), - SILC_STR_UI_INT(d_len), - SILC_STR_UI_XNSTRING(db, d_len), - SILC_STR_UI_INT(dp_len), - SILC_STR_UI_XNSTRING(dpb, dp_len), - SILC_STR_UI_INT(dq_len), - SILC_STR_UI_XNSTRING(dqb, dq_len), - SILC_STR_UI_INT(qp_len), - SILC_STR_UI_XNSTRING(qpb, qp_len), - SILC_STR_UI_INT(p_len), - SILC_STR_UI_XNSTRING(pb, p_len), - SILC_STR_UI_INT(q_len), - SILC_STR_UI_XNSTRING(qb, q_len), - SILC_STR_END) < 0) + if (silc_buffer_sformat(stack, buf, + SILC_STR_UI_INT(SILC_PRIVATE_KEY_VERSION_1), + SILC_STR_UI_INT(e_len), + SILC_STR_UI_XNSTRING(eb, e_len), + SILC_STR_UI_INT(n_len), + SILC_STR_UI_XNSTRING(nb, n_len), + SILC_STR_UI_INT(d_len), + SILC_STR_UI_XNSTRING(db, d_len), + SILC_STR_UI_INT(dp_len), + SILC_STR_UI_XNSTRING(dpb, dp_len), + SILC_STR_UI_INT(dq_len), + SILC_STR_UI_XNSTRING(dqb, dq_len), + SILC_STR_UI_INT(qp_len), + SILC_STR_UI_XNSTRING(qpb, qp_len), + SILC_STR_UI_INT(p_len), + SILC_STR_UI_XNSTRING(pb, p_len), + SILC_STR_UI_INT(q_len), + SILC_STR_UI_XNSTRING(qb, q_len), + SILC_STR_END) < 0) goto err; key = silc_buffer_steal(buf, &key_len); - silc_buffer_free(buf); + silc_buffer_sfree(stack, buf); silc_free(nb); silc_free(eb); silc_free(db); @@ -1463,7 +1532,7 @@ unsigned char *silc_pkcs_silc_export_private_key(void *private_key, silc_free(pb); silc_free(qb); - } else if (!strcmp(pkcs->name, "dsa")) { + } else if (!strcmp(alg->name, "dsa")) { SILC_NOT_IMPLEMENTED("SILC DSA Private Key"); goto err; @@ -1473,49 +1542,49 @@ unsigned char *silc_pkcs_silc_export_private_key(void *private_key, } /* Encode SILC private key */ - totlen = 2 + strlen(pkcs->name) + key_len; - buf = silc_buffer_alloc_size(totlen); + totlen = 2 + strlen(alg->name) + key_len; + buf = silc_buffer_salloc_size(stack, totlen); if (!buf) goto err; - if (silc_buffer_format(buf, - SILC_STR_UI_SHORT(strlen(pkcs->name)), - SILC_STR_UI32_STRING(pkcs->name), - SILC_STR_UI_XNSTRING(key, key_len), - SILC_STR_END) < 0) + if (silc_buffer_sformat(stack, buf, + SILC_STR_UI_SHORT(strlen(alg->name)), + SILC_STR_UI32_STRING(alg->name), + SILC_STR_UI_XNSTRING(key, key_len), + SILC_STR_END) < 0) goto err; ret = silc_buffer_steal(buf, ret_len); - silc_buffer_free(buf); - silc_free(prv); - silc_free(key); + silc_buffer_sfree(stack, buf); + silc_sfree(stack, prv); + silc_sfree(stack, key); silc_asn1_free(asn1); return ret; err: - silc_free(prv); - silc_free(key); - if (buf) - silc_buffer_free(buf); + silc_sfree(stack, prv); + silc_sfree(stack, key); + silc_buffer_sfree(stack, buf); return NULL; } /* Return key length */ -SilcUInt32 silc_pkcs_silc_private_key_bitlen(void *private_key) +SILC_PKCS_PRIVATE_KEY_BITLEN(silc_pkcs_silc_private_key_bitlen) { SilcSILCPrivateKey silc_privkey = private_key; - return silc_privkey->pkcs->private_key_bitlen(silc_privkey->private_key); + return silc_privkey->pkcs->private_key_bitlen(silc_privkey->pkcs, + silc_privkey->private_key); } /* Frees private key */ -void silc_pkcs_silc_private_key_free(void *private_key) +SILC_PKCS_PRIVATE_KEY_FREE(silc_pkcs_silc_private_key_free) { SilcSILCPrivateKey silc_privkey = private_key; - silc_privkey->pkcs->private_key_free(silc_privkey->private_key); - + silc_privkey->pkcs->private_key_free(silc_privkey->pkcs, + silc_privkey->private_key); silc_free(silc_privkey); } @@ -1524,78 +1593,68 @@ void silc_pkcs_silc_private_key_free(void *private_key) /* Encrypts as specified in SILC protocol specification */ -SilcBool silc_pkcs_silc_encrypt(void *public_key, - unsigned char *src, - SilcUInt32 src_len, - unsigned char *dst, - SilcUInt32 dst_size, - SilcUInt32 *ret_dst_len) +SILC_PKCS_ENCRYPT(silc_pkcs_silc_encrypt) { SilcSILCPublicKey silc_pubkey = public_key; - if (!silc_pubkey->pkcs->encrypt) - return FALSE; + if (!silc_pubkey->pkcs->encrypt) { + encrypt_cb(FALSE, NULL, 0, context); + return NULL; + } - return silc_pubkey->pkcs->encrypt(silc_pubkey->public_key, - src, src_len, - dst, dst_size, ret_dst_len); + return silc_pubkey->pkcs->encrypt(silc_pubkey->pkcs, + silc_pubkey->public_key, + src, src_len, rng, encrypt_cb, context); } /* Decrypts as specified in SILC protocol specification */ -SilcBool silc_pkcs_silc_decrypt(void *private_key, - unsigned char *src, - SilcUInt32 src_len, - unsigned char *dst, - SilcUInt32 dst_size, - SilcUInt32 *ret_dst_len) +SILC_PKCS_DECRYPT(silc_pkcs_silc_decrypt) { SilcSILCPrivateKey silc_privkey = private_key; - if (!silc_privkey->pkcs->decrypt) - return FALSE; + if (!silc_privkey->pkcs->decrypt) { + decrypt_cb(FALSE, NULL, 0, context); + return NULL; + } - return silc_privkey->pkcs->decrypt(silc_privkey->private_key, - src, src_len, - dst, dst_size, ret_dst_len); + return silc_privkey->pkcs->decrypt(silc_privkey->pkcs, + silc_privkey->private_key, + src, src_len, decrypt_cb, context); } /* Signs as specified in SILC protocol specification */ -SilcBool silc_pkcs_silc_sign(void *private_key, - unsigned char *src, - SilcUInt32 src_len, - unsigned char *signature, - SilcUInt32 signature_size, - SilcUInt32 *ret_signature_len, - SilcHash hash) +SILC_PKCS_SIGN(silc_pkcs_silc_sign) { SilcSILCPrivateKey silc_privkey = private_key; - if (!silc_privkey->pkcs->sign) - return FALSE; + if (!silc_privkey->pkcs->sign) { + sign_cb(FALSE, NULL, 0, context); + return NULL; + } - return silc_privkey->pkcs->sign(silc_privkey->private_key, + return silc_privkey->pkcs->sign(silc_privkey->pkcs, + silc_privkey->private_key, src, src_len, - signature, signature_size, - ret_signature_len, hash); + compute_hash, hash, rng, + sign_cb, context); } /* Verifies as specified in SILC protocol specification */ -SilcBool silc_pkcs_silc_verify(void *public_key, - unsigned char *signature, - SilcUInt32 signature_len, - unsigned char *data, - SilcUInt32 data_len, - SilcHash hash) +SILC_PKCS_VERIFY(silc_pkcs_silc_verify) { SilcSILCPublicKey silc_pubkey = public_key; - if (!silc_pubkey->pkcs->verify) - return FALSE; + if (!silc_pubkey->pkcs->verify) { + verify_cb(FALSE, context); + return NULL; + } - return silc_pubkey->pkcs->verify(silc_pubkey->public_key, + return silc_pubkey->pkcs->verify(silc_pubkey->pkcs, + silc_pubkey->public_key, signature, signature_len, - data, data_len, hash); + data, data_len, hash, rng, + verify_cb, context); }