Added PKCS #1 with hash OID support.
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
/* Default hash functions for silc_hash_register_default(). */
const SilcHashObject silc_default_hash[] =
{
- { "sha256", 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
+ { "sha256", "2.16.840.1.101.3.4.2.1",
+ 32, 64, silc_sha256_init, silc_sha256_update, silc_sha256_final,
silc_sha256_transform, silc_sha256_context_len },
- { "sha1", 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
+ { "sha1", "1.3.14.3.2.26",
+ 20, 64, silc_sha1_init, silc_sha1_update, silc_sha1_final,
silc_sha1_transform, silc_sha1_context_len },
- { "md5", 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
+ { "md5", "1.2.840.113549.2.5",
+ 16, 64, silc_md5_init, silc_md5_update, silc_md5_final,
silc_md5_transform, silc_md5_context_len },
- { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
+ { NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL }
};
/* Registers a new hash function into the SILC. This function is used at
silc_free(new);
return FALSE;
}
+ new->oid = strdup(hash->oid);
+ if (!new->oid) {
+ silc_free(new);
+ return FALSE;
+ }
new->hash_len = hash->hash_len;
new->block_len = hash->block_len;
new->init = hash->init;
{
SilcHashObject *entry = NULL;
- SILC_LOG_DEBUG(("Allocating new hash object"));
+ SILC_LOG_DEBUG(("Allocating new hash %s", name));
#ifndef SILC_SYMBIAN
if (silc_hash_list) {
return FALSE;
}
+/* Allocate hash by OID string */
+
+SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash)
+{
+ SilcHashObject *entry = NULL;
+
+ SILC_LOG_DEBUG(("Allocating new hash %s", oid));
+
+#ifndef SILC_SYMBIAN
+ if (silc_hash_list) {
+ silc_dlist_start(silc_hash_list);
+ while ((entry = silc_dlist_get(silc_hash_list)) != SILC_LIST_END) {
+ if (!strcmp(entry->oid, oid))
+ break;
+ }
+ }
+#else
+ {
+ /* On EPOC which don't have globals we check our constant hash list. */
+ int i;
+ for (i = 0; silc_default_hash[i].oid; i++) {
+ if (!strcmp(silc_default_hash[i].oid, oid)) {
+ entry = (SilcHashObject *)&(silc_default_hash[i]);
+ break;
+ }
+ }
+ }
+#endif /* SILC_SYMBIAN */
+
+ if (entry) {
+ *new_hash = silc_calloc(1, sizeof(**new_hash));
+ if (!(*new_hash))
+ return FALSE;
+ (*new_hash)->hash = entry;
+ (*new_hash)->context = silc_calloc(1, entry->context_len());
+ if (!(*new_hash)->context) {
+ silc_free(*new_hash);
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/* Free's the SilcHash object */
void silc_hash_free(SilcHash hash)
return hash->hash->name;
}
+/* Returns hash OID string */
+
+const char *silc_hash_get_oid(SilcHash hash)
+{
+ return hash->hash->oid;
+}
+
/* Returns TRUE if hash algorithm `name' is supported. */
SilcBool silc_hash_is_supported(const unsigned char *name)
Author: Pekka Riikonen <priikone@silcnet.org>
- Copyright (C) 1997 - 2005 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
***/
typedef struct {
char *name;
- SilcUInt32 hash_len;
- SilcUInt32 block_len;
+ char *oid;
+ SilcUInt16 hash_len;
+ SilcUInt16 block_len;
void (*init)(void *);
void (*update)(void *, const unsigned char *, SilcUInt32);
***/
SilcBool silc_hash_alloc(const unsigned char *name, SilcHash *new_hash);
+/****f* silccrypt/SilcHashAPI/silc_hash_alloc_by_oid
+ *
+ * SYNOPSIS
+ *
+ * SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash);
+ *
+ * DESCRIPTION
+ *
+ * Same as silc_hash_alloc but allocates the hash algorithm by the
+ * hash algorithm OID string indicated by `oid'. Returns FALSE if such
+ * hash function does not exist.
+ *
+ ***/
+SilcBool silc_hash_alloc_by_oid(const char *oid, SilcHash *new_hash);
+
/****f* silccrypt/SilcHashAPI/silc_hash_free
*
* SYNOPSIS
***/
const char *silc_hash_get_name(SilcHash hash);
+/****f* silccrypt/SilcHashAPI/silc_hash_get_oid
+ *
+ * SYNOPSIS
+ *
+ * const char *silc_hash_get_name(SilcHash hash);
+ *
+ * DESCRIPTION
+ *
+ * Returns the hash OID string. Returns NULL if the hash doesn't have
+ * OID string. Use strlen() to get the OID string length.
+ *
+ ***/
+const char *silc_hash_get_oid(SilcHash hash);
+
/****f* silccrypt/SilcHashAPI/silc_hash_make
*
* SYNOPSIS
/* 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,
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));
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));
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)
char *silc_pkcs_silc_encode_identifier(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)
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) < 3 || strlen(host) < 3)
return NULL;
- len += 3 + 5 + 5 + 4 + 4 + 4;
- buf = silc_buffer_alloc(len);
- if (!buf)
- return NULL;
- silc_buffer_pull_tail(buf, len);
+ memset(&buf, 0, sizeof(buf));
- if (username) {
- silc_buffer_format(buf,
+ if (username)
+ silc_buffer_format(&buf,
+ SILC_STR_ADVANCE,
SILC_STR_UI32_STRING("UN="),
SILC_STR_UI32_STRING(username),
SILC_STR_END);
- silc_buffer_pull(buf, 3 + strlen(username));
- tlen = 3 + strlen(username);
- }
- if (host) {
- silc_buffer_format(buf,
+ if (host)
+ silc_buffer_format(&buf,
+ SILC_STR_ADVANCE,
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);
- }
- if (realname) {
- silc_buffer_format(buf,
+ if (realname)
+ silc_buffer_format(&buf,
+ SILC_STR_ADVANCE,
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);
- }
- if (email) {
- silc_buffer_format(buf,
+ if (email)
+ silc_buffer_format(&buf,
+ SILC_STR_ADVANCE,
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);
- }
- if (org) {
- silc_buffer_format(buf,
+ if (org)
+ silc_buffer_format(&buf,
+ SILC_STR_ADVANCE,
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);
- }
- if (country) {
- silc_buffer_format(buf,
+ if (country)
+ silc_buffer_format(&buf,
+ SILC_STR_ADVANCE,
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 (version) {
+ if (strlen(version) > 1 || !isdigit(version[0])) {
+ silc_buffer_purge(&buf);
+ return NULL;
+ }
+ silc_buffer_format(&buf,
+ SILC_STR_ADVANCE,
+ SILC_STR_UI32_STRING(", "),
+ SILC_STR_UI32_STRING("V="),
+ SILC_STR_UI32_STRING(version),
+ SILC_STR_END);
}
- 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_buffer_format(&buf, SILC_STR_UI_CHAR(0), SILC_STR_END);
+ identifier = silc_buffer_steal(&buf, NULL);
return identifier;
}
+/* Return SILC public key version */
+
+int silc_pkcs_silc_public_key_version(SilcPublicKey public_key)
+{
+ SilcSILCPublicKey silc_pubkey;
+
+ if (silc_pkcs_get_type(public_key) != SILC_PKCS_SILC)
+ return -1;
+
+ silc_pubkey = public_key->public_key;
+
+ /* 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 *****************************/
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");
+ /* 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 */
+ pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
+ } else {
+ /* Version 2 and newer */
+ pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
+ }
if (!pkcs) {
SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
goto err;
silc_pubkey->identifier.realname,
silc_pubkey->identifier.email,
silc_pubkey->identifier.org,
- silc_pubkey->identifier.country);
+ silc_pubkey->identifier.country,
+ silc_pubkey->identifier.version);
if (!identifier)
goto err;
strcmp(k1->identifier.country, k2->identifier.country)))
return FALSE;
+ 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->public_key, k2->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);
}
/* Private key version */
#define SILC_PRIVATE_KEY_VERSION_1 0x82171273
+#define SILC_PRIVATE_KEY_VERSION_2 0xf911a3d1
/* Imports SILC implementation style private 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
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),
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 */
+ pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1-no-oid");
+ } else {
+ /* Version 2 and newer */
+ pkcs = silc_pkcs_find_algorithm(pkcs_name, "pkcs1");
+ }
+ if (!pkcs) {
+ SILC_LOG_DEBUG(("Unsupported PKCS algorithm"));
+ goto err;
+ }
+ silc_privkey->pkcs = pkcs;
+
+ 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);
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);
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);
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);
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 */
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);
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);
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);
unsigned char *signature,
SilcUInt32 signature_size,
SilcUInt32 *ret_signature_len,
+ SilcBool compute_hash,
SilcHash hash)
{
SilcSILCPrivateKey silc_privkey = private_key;
return silc_privkey->pkcs->sign(silc_privkey->private_key,
src, src_len,
signature, signature_size,
- ret_signature_len, hash);
+ ret_signature_len, compute_hash, hash);
}
/* Verifies as specified in SILC protocol specification */
Author: Pekka Riikonen <priikone@silcnet.org>
- 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
char *email;
char *org;
char *country;
+ char *version;
} *SilcPublicKeyIdentifier, SilcPublicKeyIdentifierStruct;
/***/
* SYNOPSIS
*
* SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
- * const char *scheme,
* SilcUInt32 bits_key_len,
* const char *identifier,
* SilcRng rng,
*
* // Generate RSA key pair with 2048 bit key length, using PKCS #1
* // no OID scheme.
- * silc_pkcs_silc_generate_key("rsa", "pkcs1-no-oid", 2048,
- * rng, &public_key, &private_key);
+ * silc_pkcs_silc_generate_key("rsa", 2048, rng, &public_key, &private_key);
*
***/
SilcBool silc_pkcs_silc_generate_key(const char *algorithm,
- const char *scheme,
SilcUInt32 bits_key_len,
const char *identifier,
SilcRng rng,
*
* char *silc_pkcs_silc_encode_identifier(char *username, char *host,
* char *realname, char *email,
- * char *org, char *country)
+ * char *org, char *country,
+ * char *version);
*
* DESCRIPTION
*
***/
char *silc_pkcs_silc_encode_identifier(char *username, char *host,
char *realname, char *email,
- char *org, char *country);
+ char *org, char *country,
+ char *version);
/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_decode_identifier
*
SilcBool silc_pkcs_silc_decode_identifier(const char *identifier,
SilcPublicKeyIdentifier ident);
+/****f* silccrypt/SilcPubkeyAPI/silc_pkcs_silc_public_key_version
+ *
+ * SYNOPSIS
+ *
+ * int silc_pkcs_silc_public_key_version(SilcPublicKey public_key);
+ *
+ * DESCRIPTION
+ *
+ * Returns the verison of the SILC Public Key indicated by `public_key'.
+ * Returns -1 if the `public_key' is not a SILC Public Key and the
+ * version number otherwise.
+ *
+ ***/
+int silc_pkcs_silc_public_key_version(SilcPublicKey public_key);
+
#endif /* SILCPK_H */
unsigned char *signature,
SilcUInt32 signature_size,
SilcUInt32 *ret_signature_len,
+ SilcBool compute_hash,
SilcHash hash);
SilcBool silc_pkcs_silc_verify(void *public_key,
unsigned char *signature,
SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
unsigned char *src, SilcUInt32 src_len,
unsigned char *dst, SilcUInt32 dst_size,
- SilcUInt32 *dst_len, SilcHash hash)
+ SilcUInt32 *dst_len, SilcBool compute_hash,
+ SilcHash hash)
{
return private_key->pkcs->sign(private_key->private_key, src, src_len,
- dst, dst_size, dst_len, hash);
+ dst, dst_size, dst_len, compute_hash, hash);
}
/* Verifies signature */
unsigned char *signature,
SilcUInt32 signature_size,
SilcUInt32 *ret_signature_len,
+ SilcBool compute_hash,
SilcHash hash);
SilcBool (*verify)(void *public_key,
unsigned char *signature,
unsigned char *signature,
SilcUInt32 signature_size,
SilcUInt32 *ret_signature_len,
+ SilcBool compute_hash,
SilcHash hash);
SilcBool (*verify)(void *public_key,
unsigned char *signature,
* SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
* unsigned char *src, SilcUInt32 src_len,
* unsigned char *dst, SilcUInt32 dst_size,
- * SilcUInt32 *dst_len, SilcHash hash);
+ * SilcUInt32 *dst_len, SilcBool compute_hash,
+ * SilcHash hash);
*
* DESCRIPTION
*
* Generates signature with the private key. Returns FALSE on error.
- * If `hash' is non-NULL the `src' will be hashed before signing.
+ * If `compute_hash' is TRUE the `hash' will be used to compute a
+ * digest over the `src'. The `hash' must always be valid.
*
***/
SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
unsigned char *src, SilcUInt32 src_len,
unsigned char *dst, SilcUInt32 dst_size,
- SilcUInt32 *dst_len, SilcHash hash);
+ SilcUInt32 *dst_len, SilcBool compute_hash,
+ SilcHash hash);
/****f* silccrypt/SilcPKCSAPI/silc_pkcs_verify
*
goto err;
/* Set key length */
- pubkey->bits = silc_mp_sizeinbase(&pubkey->n, 2);
+ pubkey->bits = ((silc_mp_sizeinbase(&pubkey->n, 2) + 7) / 8) * 8;
silc_asn1_free(asn1);
goto err;
/* Set key length */
- privkey->bits = silc_mp_sizeinbase(&privkey->n, 2);
+ privkey->bits = ((silc_mp_sizeinbase(&privkey->n, 2) + 7) / 8) * 8;
silc_asn1_free(asn1);
unsigned char *signature,
SilcUInt32 signature_size,
SilcUInt32 *ret_signature_len,
+ SilcBool compute_hash,
SilcHash hash)
{
- return FALSE;
+ RsaPrivateKey *key = private_key;
+ unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
+ SilcMPInt mp_tmp;
+ SilcMPInt mp_dst;
+ SilcBufferStruct di;
+ SilcUInt32 len = (key->bits + 7) / 8;
+ const char *oid;
+ SilcAsn1 asn1;
+
+ SILC_LOG_DEBUG(("Sign"));
+
+ if (sizeof(padded) < len)
+ return FALSE;
+ if (signature_size < len)
+ return FALSE;
+
+ oid = silc_hash_get_oid(hash);
+ if (!oid)
+ return FALSE;
+
+ asn1 = silc_asn1_alloc();
+ if (!asn1)
+ return FALSE;
+
+ /* Compute hash */
+ if (compute_hash) {
+ silc_hash_make(hash, src, src_len, hashr);
+ src = hashr;
+ src_len = silc_hash_len(hash);
+ }
+
+ /* Encode digest info */
+ memset(&di, 0, sizeof(di));
+ if (!silc_asn1_encode(asn1, &di,
+ SILC_ASN1_SEQUENCE,
+ SILC_ASN1_SEQUENCE,
+ SILC_ASN1_OID(oid),
+ SILC_ASN1_NULL,
+ SILC_ASN1_END,
+ SILC_ASN1_OCTET_STRING(src, src_len),
+ SILC_ASN1_END, SILC_ASN1_END)) {
+ silc_asn1_free(asn1);
+ return FALSE;
+ }
+ SILC_LOG_HEXDUMP(("DigestInfo"), silc_buffer_data(&di),
+ silc_buffer_len(&di));
+
+ /* Pad data */
+ if (!silc_pkcs1_encode(SILC_PKCS1_BT_PRV1, silc_buffer_data(&di),
+ silc_buffer_len(&di), padded, len, NULL)) {
+ silc_asn1_free(asn1);
+ return FALSE;
+ }
+
+ silc_mp_init(&mp_tmp);
+ silc_mp_init(&mp_dst);
+
+ /* Data to MP */
+ silc_mp_bin2mp(padded, len, &mp_tmp);
+
+ /* Sign */
+ silc_rsa_private_operation(key, &mp_tmp, &mp_dst);
+
+ /* MP to data */
+ silc_mp_mp2bin_noalloc(&mp_dst, signature, len);
+ *ret_signature_len = len;
+
+ memset(padded, 0, sizeof(padded));
+ silc_mp_uninit(&mp_tmp);
+ silc_mp_uninit(&mp_dst);
+ if (compute_hash)
+ memset(hashr, 0, sizeof(hashr));
+ silc_asn1_free(asn1);
+
+ return TRUE;
}
/* PKCS #1 verification with appendix. */
SilcUInt32 data_len,
SilcHash hash)
{
+ RsaPublicKey *key = public_key;
+ SilcBool ret = FALSE;
+ SilcMPInt mp_tmp2;
+ SilcMPInt mp_dst;
+ unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN];
+ SilcUInt32 verify_len, len = (key->bits + 7) / 8;
+ SilcBufferStruct di, ldi;
+ SilcHash ihash = NULL;
+ SilcAsn1 asn1 = NULL;
+ char *oid;
+
+ SILC_LOG_DEBUG(("Verify signature"));
+
+ asn1 = silc_asn1_alloc();
+ if (!asn1)
+ return FALSE;
+
+ silc_mp_init(&mp_tmp2);
+ silc_mp_init(&mp_dst);
+
+ /* Format the signature into MP int */
+ silc_mp_bin2mp(signature, signature_len, &mp_tmp2);
+
+ /* Verify */
+ silc_rsa_public_operation(key, &mp_tmp2, &mp_dst);
+
+ /* MP to data */
+ verify = silc_mp_mp2bin(&mp_dst, len, &verify_len);
+
+ /* Unpad data */
+ if (!silc_pkcs1_decode(SILC_PKCS1_BT_PRV1, verify, verify_len,
+ unpadded, sizeof(unpadded), &len))
+ goto err;
+ silc_buffer_set(&di, unpadded, len);
+
+ /* If hash isn't given, allocate the one given in digest info */
+ if (!hash) {
+ /* Decode digest info */
+ if (!silc_asn1_decode(asn1, &di,
+ SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
+ SILC_ASN1_SEQUENCE,
+ SILC_ASN1_SEQUENCE,
+ SILC_ASN1_OID(&oid),
+ SILC_ASN1_END,
+ SILC_ASN1_END, SILC_ASN1_END))
+ goto err;
+
+ if (!silc_hash_alloc_by_oid(oid, &ihash)) {
+ SILC_LOG_DEBUG(("Unknown OID %s", oid));
+ goto err;
+ }
+ hash = ihash;
+ }
+
+ /* Hash the data */
+ silc_hash_make(hash, data, data_len, hashr);
+ data = hashr;
+ data_len = silc_hash_len(hash);
+ oid = (char *)silc_hash_get_oid(hash);
+
+ /* Encode digest info for comparison */
+ memset(&ldi, 0, sizeof(ldi));
+ if (!silc_asn1_encode(asn1, &ldi,
+ SILC_ASN1_OPTS(SILC_ASN1_ACCUMUL),
+ SILC_ASN1_SEQUENCE,
+ SILC_ASN1_SEQUENCE,
+ SILC_ASN1_OID(oid),
+ SILC_ASN1_NULL,
+ SILC_ASN1_END,
+ SILC_ASN1_OCTET_STRING(data, data_len),
+ SILC_ASN1_END, SILC_ASN1_END))
+ goto err;
+
+ SILC_LOG_HEXDUMP(("DigestInfo remote"), silc_buffer_data(&di),
+ silc_buffer_len(&di));
+ SILC_LOG_HEXDUMP(("DigestInfo local"), silc_buffer_data(&ldi),
+ silc_buffer_len(&ldi));
+
+ /* Compare */
+ if (silc_buffer_len(&di) == silc_buffer_len(&ldi) &&
+ !memcmp(silc_buffer_data(&di), silc_buffer_data(&ldi),
+ silc_buffer_len(&ldi)))
+ ret = TRUE;
+
+ memset(verify, 0, verify_len);
+ memset(unpadded, 0, sizeof(unpadded));
+ silc_free(verify);
+ silc_mp_uninit(&mp_tmp2);
+ silc_mp_uninit(&mp_dst);
+ if (hash)
+ memset(hashr, 0, sizeof(hashr));
+ if (ihash)
+ silc_hash_free(ihash);
+ silc_asn1_free(asn1);
+
+ return ret;
+
+ err:
+ memset(verify, 0, verify_len);
+ silc_free(verify);
+ silc_mp_uninit(&mp_tmp2);
+ silc_mp_uninit(&mp_dst);
+ if (ihash)
+ silc_hash_free(ihash);
+ silc_asn1_free(asn1);
return FALSE;
}
unsigned char *signature,
SilcUInt32 signature_size,
SilcUInt32 *ret_signature_len,
+ SilcBool compute_hash,
SilcHash hash)
{
RsaPrivateKey *key = private_key;
unsigned char padded[2048 + 1], hashr[SILC_HASH_MAXLEN];
SilcUInt32 len = (key->bits + 7) / 8;
+ SILC_LOG_DEBUG(("Sign"));
+
if (sizeof(padded) < len)
return FALSE;
if (signature_size < len)
return FALSE;
/* Compute hash if requested */
- if (hash) {
+ if (compute_hash) {
silc_hash_make(hash, src, src_len, hashr);
src = hashr;
src_len = silc_hash_len(hash);
memset(padded, 0, sizeof(padded));
silc_mp_uninit(&mp_tmp);
silc_mp_uninit(&mp_dst);
- if (hash)
+ if (compute_hash)
memset(hashr, 0, sizeof(hashr));
return TRUE;
SilcHash hash)
{
RsaPublicKey *key = public_key;
- int ret = TRUE;
+ SilcBool ret = FALSE;
SilcMPInt mp_tmp2;
SilcMPInt mp_dst;
unsigned char *verify, unpadded[2048 + 1], hashr[SILC_HASH_MAXLEN];
SilcUInt32 verify_len, len = (key->bits + 7) / 8;
+ SILC_LOG_DEBUG(("Verify signature"));
+
silc_mp_init(&mp_tmp2);
silc_mp_init(&mp_dst);
}
/* Compare */
- if (len != data_len)
- ret = FALSE;
- else if (memcmp(data, unpadded, len))
- ret = FALSE;
+ if (len == data_len && !memcmp(data, unpadded, len))
+ ret = TRUE;
memset(verify, 0, verify_len);
memset(unpadded, 0, sizeof(unpadded));
unsigned char *signature,
SilcUInt32 signature_size,
SilcUInt32 *ret_signature_len,
+ SilcBool compute_hash,
SilcHash hash);
SilcBool silc_pkcs1_verify(void *public_key,
unsigned char *signature,
unsigned char *signature,
SilcUInt32 signature_size,
SilcUInt32 *ret_signature_len,
+ SilcBool compute_hash,
SilcHash hash);
SilcBool silc_pkcs1_verify_no_oid(void *public_key,
unsigned char *signature,