X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilccrypt%2Fsilcpkcs.c;h=4deddfd96f33b063277784024cd7f1861b4bb98d;hp=891e9afaeb443ec35fa566707fa3f7025f2d1154;hb=382d15d447b7a95390decfa783836ae4fe255b3d;hpb=fde8aa8c7b1952d14fe9275ae36836fe995ea943 diff --git a/lib/silccrypt/silcpkcs.c b/lib/silccrypt/silcpkcs.c index 891e9afa..4deddfd9 100644 --- a/lib/silccrypt/silcpkcs.c +++ b/lib/silccrypt/silcpkcs.c @@ -620,6 +620,7 @@ SilcPublicKey silc_pkcs_public_key_alloc(const char *name, public_key->name = strdup(name); public_key->pk_len = pk_len; public_key->pk = silc_calloc(pk_len, sizeof(*public_key->pk)); + public_key->pk_type = SILC_SKE_PK_TYPE_SILC; memcpy(public_key->pk, pk, pk_len); if (!silc_utf8_valid(identifier, strlen(identifier))) { @@ -630,7 +631,7 @@ SilcPublicKey silc_pkcs_public_key_alloc(const char *name, } public_key->identifier = strdup(identifier); - public_key->len = 4 + 2 + strlen(name) + 2 + strlen(identifier) + pk_len; + public_key->len = 2 + strlen(name) + 2 + strlen(identifier) + pk_len; silc_free(tmp); return public_key; @@ -686,7 +687,7 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len) SilcBuffer buf; unsigned char *ret; - buf = silc_buffer_alloc(public_key->len); + buf = silc_buffer_alloc(public_key->len + 4); silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); silc_buffer_format(buf, @@ -699,7 +700,7 @@ silc_pkcs_public_key_encode(SilcPublicKey public_key, SilcUInt32 *len) public_key->pk_len), SILC_STR_END); if (len) - *len = public_key->len; + *len = public_key->len + 4; ret = silc_calloc(buf->len, sizeof(*ret)); memcpy(ret, buf->data, buf->len); @@ -719,8 +720,8 @@ silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len, unsigned char *ret; SilcUInt32 totlen; - totlen = 4 + 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len; - buf = silc_buffer_alloc(totlen); + totlen = 2 + strlen(pkcs) + 2 + strlen(identifier) + pk_len; + buf = silc_buffer_alloc(totlen + 4); silc_buffer_pull_tail(buf, SILC_BUFFER_END(buf)); silc_buffer_format(buf, @@ -732,7 +733,7 @@ silc_pkcs_public_key_data_encode(unsigned char *pk, SilcUInt32 pk_len, SILC_STR_UI_XNSTRING(pk, pk_len), SILC_STR_END); if (len) - *len = totlen; + *len = totlen + 4; ret = silc_calloc(buf->len, sizeof(*ret)); memcpy(ret, buf->data, buf->len); @@ -767,7 +768,12 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, return FALSE; } - if (totlen != data_len) { +#if 1 /* Backwards support, remove! */ + if (totlen == data_len) + totlen -= 4; +#endif + + if (totlen + 4 != data_len) { silc_buffer_free(buf); return FALSE; } @@ -826,6 +832,7 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, (*public_key)->identifier = ident; (*public_key)->pk = key_data; (*public_key)->pk_len = key_len; + (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC; } silc_buffer_free(buf); @@ -842,6 +849,79 @@ bool silc_pkcs_public_key_decode(unsigned char *data, SilcUInt32 data_len, return FALSE; } +/* Encodes Public Key Payload for transmitting public keys and certificates. */ + +SilcBuffer silc_pkcs_public_key_payload_encode(SilcPublicKey public_key) +{ + SilcBuffer buffer; + unsigned char *pk; + SilcUInt32 pk_len; + + if (!public_key) + return NULL; + + pk = silc_pkcs_public_key_encode(public_key, &pk_len); + if (!pk) + return NULL; + + buffer = silc_buffer_alloc_size(4 + pk_len); + if (!buffer) { + silc_free(pk); + return NULL; + } + + silc_buffer_format(buffer, + SILC_STR_UI_SHORT(pk_len), + SILC_STR_UI_SHORT(public_key->pk_type), + SILC_STR_UI_XNSTRING(pk, pk_len), + SILC_STR_END); + + silc_free(pk); + return buffer; +} + +/* Decode Public Key Payload and decodes the public key inside it to + to `payload'. */ + +bool silc_pkcs_public_key_payload_decode(unsigned char *data, + SilcUInt32 data_len, + SilcPublicKey *public_key) +{ + SilcBufferStruct buf; + SilcUInt16 pk_len, pk_type; + unsigned char *pk; + int ret; + + if (!public_key) + return FALSE; + + silc_buffer_set(&buf, data, data_len); + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_SHORT(&pk_len), + SILC_STR_UI_SHORT(&pk_type), + SILC_STR_END); + if (ret < 0 || pk_len > data_len - 4) + return FALSE; + + /* For now we support only SILC public keys */ + if (pk_type != SILC_SKE_PK_TYPE_SILC) + return FALSE; + + silc_buffer_pull(&buf, 4); + ret = silc_buffer_unformat(&buf, + SILC_STR_UI_XNSTRING(&pk, pk_len), + SILC_STR_END); + silc_buffer_push(&buf, 4); + if (ret < 0) + return FALSE; + + if (!silc_pkcs_public_key_decode(pk, pk_len, public_key)) + return FALSE; + (*public_key)->pk_type = SILC_SKE_PK_TYPE_SILC; + + return TRUE; +} + /* Compares two public keys and returns TRUE if they are same key, and FALSE if they are not same. */ @@ -876,6 +956,7 @@ SilcPublicKey silc_pkcs_public_key_copy(SilcPublicKey public_key) strlen(public_key->identifier)); key->pk = silc_memdup(public_key->pk, public_key->pk_len); key->pk_len = public_key->pk_len; + key->pk_type = public_key->pk_type; return key; } @@ -1022,7 +1103,7 @@ bool silc_pkcs_private_key_decode(unsigned char *data, SilcUInt32 data_len, /* Internal routine to save public key */ -static bool silc_pkcs_save_public_key_internal(char *filename, +static bool silc_pkcs_save_public_key_internal(const char *filename, unsigned char *data, SilcUInt32 data_len, SilcUInt32 encoding) @@ -1062,7 +1143,7 @@ static bool silc_pkcs_save_public_key_internal(char *filename, /* Saves public key into file */ -bool silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key, +bool silc_pkcs_save_public_key(const char *filename, SilcPublicKey public_key, SilcUInt32 encoding) { unsigned char *data; @@ -1078,9 +1159,8 @@ bool silc_pkcs_save_public_key(char *filename, SilcPublicKey public_key, /* Saves public key into file */ -bool silc_pkcs_save_public_key_data(char *filename, unsigned char *data, - SilcUInt32 data_len, - SilcUInt32 encoding) +bool silc_pkcs_save_public_key_data(const char *filename, unsigned char *data, + SilcUInt32 data_len, SilcUInt32 encoding) { return silc_pkcs_save_public_key_internal(filename, data, data_len, encoding); @@ -1090,7 +1170,7 @@ bool silc_pkcs_save_public_key_data(char *filename, unsigned char *data, /* Internal routine to save private key. */ -static bool silc_pkcs_save_private_key_internal(char *filename, +static bool silc_pkcs_save_private_key_internal(const char *filename, unsigned char *data, SilcUInt32 data_len, unsigned char *key, @@ -1098,11 +1178,11 @@ static bool silc_pkcs_save_private_key_internal(char *filename, SilcUInt32 encoding) { SilcCipher aes; - SilcHash md5; + SilcHash sha1; SilcHmac sha1hmac; SilcBuffer buf, enc; - SilcUInt32 len, blocklen; - unsigned char tmp[32], keymat[32]; + SilcUInt32 len, blocklen, padlen; + unsigned char tmp[32], keymat[64]; int i; memset(tmp, 0, sizeof(tmp)); @@ -1117,9 +1197,9 @@ static bool silc_pkcs_save_private_key_internal(char *filename, if (blocklen * 2 > sizeof(tmp)) return FALSE; - /* Allocate MD5 hash */ - if (!silc_hash_alloc("md5", &md5)) { - SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered")); + /* Allocate SHA1 hash */ + if (!silc_hash_alloc("sha1", &sha1)) { + SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered")); silc_cipher_free(aes); return FALSE; } @@ -1127,7 +1207,7 @@ static bool silc_pkcs_save_private_key_internal(char *filename, /* Allocate HMAC */ if (!silc_hmac_alloc("hmac-sha1-96", NULL, &sha1hmac)) { SILC_LOG_ERROR(("Could not allocate SHA1 HMAC, probably not registered")); - silc_hash_free(md5); + silc_hash_free(sha1); silc_cipher_free(aes); return FALSE; } @@ -1136,33 +1216,33 @@ static bool silc_pkcs_save_private_key_internal(char *filename, is 256 bits length, and derived by taking hash of the data, then re-hashing the data and the previous digest, and using the first and second digest as the key. */ - silc_hash_init(md5); - silc_hash_update(md5, key, key_len); - silc_hash_final(md5, keymat); - silc_hash_init(md5); - silc_hash_update(md5, key, key_len); - silc_hash_update(md5, keymat, 16); - silc_hash_final(md5, keymat + 16); + silc_hash_init(sha1); + silc_hash_update(sha1, key, key_len); + silc_hash_final(sha1, keymat); + silc_hash_init(sha1); + silc_hash_update(sha1, key, key_len); + silc_hash_update(sha1, keymat, 16); + silc_hash_final(sha1, keymat + 16); /* Set the key to the cipher */ - silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8); + silc_cipher_set_key(aes, keymat, 256); /* Encode the buffer to be encrypted. Add padding to it too, at least block size of the cipher. */ /* Allocate buffer for encryption */ len = silc_hmac_len(sha1hmac); - enc = silc_buffer_alloc_size(data_len + 4 + 4 + - (blocklen + (data_len % blocklen)) + len); + padlen = 16 + (16 - ((data_len + 4) % blocklen)); + enc = silc_buffer_alloc_size(4 + 4 + data_len + padlen + len); if (!enc) { silc_hmac_free(sha1hmac); - silc_hash_free(md5); + silc_hash_free(sha1); silc_cipher_free(aes); return FALSE; } /* Generate padding */ - for (i = 0; i < blocklen + (data_len % blocklen); i++) + for (i = 0; i < padlen; i++) tmp[i] = silc_rng_global_get_byte_fast(); /* Put magic number */ @@ -1173,8 +1253,7 @@ static bool silc_pkcs_save_private_key_internal(char *filename, silc_buffer_format(enc, SILC_STR_UI_INT(data_len), SILC_STR_UI_XNSTRING(data, data_len), - SILC_STR_UI_XNSTRING(tmp, blocklen + (data_len % - blocklen)), + SILC_STR_UI_XNSTRING(tmp, padlen), SILC_STR_END); /* Encrypt. */ @@ -1196,7 +1275,7 @@ static bool silc_pkcs_save_private_key_internal(char *filename, memset(keymat, 0, sizeof(keymat)); memset(tmp, 0, sizeof(tmp)); silc_hmac_free(sha1hmac); - silc_hash_free(md5); + silc_hash_free(sha1); silc_cipher_free(aes); data = enc->data; @@ -1239,7 +1318,8 @@ static bool silc_pkcs_save_private_key_internal(char *filename, /* Saves private key into file. */ -bool silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, +bool silc_pkcs_save_private_key(const char *filename, + SilcPrivateKey private_key, unsigned char *passphrase, SilcUInt32 passphrase_len, SilcUInt32 encoding) @@ -1260,12 +1340,16 @@ bool silc_pkcs_save_private_key(char *filename, SilcPrivateKey private_key, /* Loads public key from file and allocates new public key. Returns TRUE if loading was successful. */ -bool silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key, +bool silc_pkcs_load_public_key(const char *filename, SilcPublicKey *public_key, SilcUInt32 encoding) { unsigned char *cp, *old, *data, byte; SilcUInt32 i, data_len, len; + SILC_LOG_DEBUG(("Loading public key `%s' with %s encoding", filename, + encoding == SILC_PKCS_FILE_PEM ? "Base64" : + encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn")); + old = data = silc_file_readfile(filename, &data_len); if (!data) return FALSE; @@ -1316,19 +1400,24 @@ bool silc_pkcs_load_public_key(char *filename, SilcPublicKey *public_key, /* Load private key from file and allocates new private key. Returns TRUE if loading was successful. */ -bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key, +bool silc_pkcs_load_private_key(const char *filename, + SilcPrivateKey *private_key, unsigned char *passphrase, SilcUInt32 passphrase_len, SilcUInt32 encoding) { SilcCipher aes; - SilcHash md5; + SilcHash sha1; SilcHmac sha1hmac; SilcUInt32 blocklen; - unsigned char tmp[32], keymat[32]; + unsigned char tmp[32], keymat[64]; unsigned char *cp, *old, *data, byte; SilcUInt32 i, data_len, len, magic, mac_len; + SILC_LOG_DEBUG(("Loading private key `%s' with %s encoding", filename, + encoding == SILC_PKCS_FILE_PEM ? "Base64" : + encoding == SILC_PKCS_FILE_BIN ? "Binary" : "Unkonwn")); + old = data = silc_file_readfile(filename, &data_len); if (!data) return FALSE; @@ -1371,6 +1460,8 @@ bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key, to be the old-style private keys that are not encrypted. */ SILC_GET32_MSB(magic, data); if (magic != SILC_PKCS_PRIVATE_KEY_MAGIC) { + SILC_LOG_DEBUG(("Private key does not have correct magic!")); + /* Now decode the actual private key */ if (!silc_pkcs_private_key_decode(data, len, private_key)) { memset(old, 0, data_len); @@ -1397,9 +1488,9 @@ bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key, return FALSE; } - /* Allocate MD5 hash */ - if (!silc_hash_alloc("md5", &md5)) { - SILC_LOG_ERROR(("Could not allocate MD5 hash, probably not registered")); + /* Allocate SHA1 hash */ + if (!silc_hash_alloc("sha1", &sha1)) { + SILC_LOG_ERROR(("Could not allocate SHA1 hash, probably not registered")); silc_cipher_free(aes); memset(old, 0, data_len); silc_free(old); @@ -1409,7 +1500,7 @@ bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *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_hash_free(md5); + silc_hash_free(sha1); silc_cipher_free(aes); memset(old, 0, data_len); silc_free(old); @@ -1420,16 +1511,16 @@ bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key, is 256 bits length, and derived by taking hash of the data, then re-hashing the data and the previous digest, and using the first and second digest as the key. */ - silc_hash_init(md5); - silc_hash_update(md5, passphrase, passphrase_len); - silc_hash_final(md5, keymat); - silc_hash_init(md5); - silc_hash_update(md5, passphrase, passphrase_len); - silc_hash_update(md5, keymat, 16); - silc_hash_final(md5, keymat + 16); + silc_hash_init(sha1); + silc_hash_update(sha1, passphrase, passphrase_len); + silc_hash_final(sha1, keymat); + silc_hash_init(sha1); + silc_hash_update(sha1, passphrase, passphrase_len); + silc_hash_update(sha1, keymat, 16); + silc_hash_final(sha1, keymat + 16); /* Set the key to the cipher */ - silc_cipher_set_key(aes, keymat, sizeof(keymat) * 8); + silc_cipher_set_key(aes, keymat, 256); /* First, verify the MAC of the private key data */ mac_len = silc_hmac_len(sha1hmac); @@ -1441,7 +1532,7 @@ bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key, memset(keymat, 0, sizeof(keymat)); memset(tmp, 0, sizeof(tmp)); silc_hmac_free(sha1hmac); - silc_hash_free(md5); + silc_hash_free(sha1); silc_cipher_free(aes); memset(old, 0, data_len); silc_free(old); @@ -1451,14 +1542,14 @@ bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key, len -= 4; /* Decrypt the private key buffer */ - silc_cipher_decrypt(aes, data, data, len - mac_len, silc_cipher_get_iv(aes)); + silc_cipher_decrypt(aes, data, data, len - mac_len, NULL); SILC_GET32_MSB(i, data); if (i > len) { SILC_LOG_DEBUG(("Bad private key length in buffer!")); memset(keymat, 0, sizeof(keymat)); memset(tmp, 0, sizeof(tmp)); silc_hmac_free(sha1hmac); - silc_hash_free(md5); + silc_hash_free(sha1); silc_cipher_free(aes); memset(old, 0, data_len); silc_free(old); @@ -1471,7 +1562,7 @@ bool silc_pkcs_load_private_key(char *filename, SilcPrivateKey *private_key, memset(keymat, 0, sizeof(keymat)); memset(tmp, 0, sizeof(tmp)); silc_hmac_free(sha1hmac); - silc_hash_free(md5); + silc_hash_free(sha1); silc_cipher_free(aes); /* Now decode the actual private key */