int silc_pkcs1_import_private_key(unsigned char *key, SilcUInt32 key_len, void **ret_private_key) { SilcAsn1 asn1; SilcBufferStruct alg_key; RsaPrivateKey *privkey; SilcUInt32 ver; if (!ret_private_key) return 0; asn1 = silc_asn1_alloc(); if (!asn1) return 0; /* Allocate RSA private key */ *ret_private_key = privkey = silc_calloc(1, sizeof(*privkey)); if (!privkey) goto err; /* Parse the PKCS #1 private key */ silc_buffer_set(&alg_key, key, key_len); if (!silc_asn1_decode(asn1, &alg_key, SILC_ASN1_OPTS(SILC_ASN1_ALLOC), SILC_ASN1_SEQUENCE, SILC_ASN1_SHORT_INT(&ver), SILC_ASN1_INT(&privkey->n), SILC_ASN1_INT(&privkey->e), SILC_ASN1_INT(&privkey->d), SILC_ASN1_INT(&privkey->p), SILC_ASN1_INT(&privkey->q), SILC_ASN1_INT(&privkey->dP), SILC_ASN1_INT(&privkey->dQ), SILC_ASN1_INT(&privkey->qP), SILC_ASN1_END, SILC_ASN1_END)) goto err; if (ver != 0) goto err; /* Set key length */ privkey->bits = ((silc_mp_sizeinbase(&privkey->n, 2) + 7) / 8) * 8; silc_asn1_free(asn1); return key_len; err: silc_free(privkey); silc_asn1_free(asn1); return 0; }
int silc_pkcs1_import_public_key(unsigned char *key, SilcUInt32 key_len, void **ret_public_key) { SilcAsn1 asn1 = NULL; SilcBufferStruct alg_key; RsaPublicKey *pubkey; if (!ret_public_key) return 0; asn1 = silc_asn1_alloc(); if (!asn1) return 0; /* Allocate RSA public key */ *ret_public_key = pubkey = silc_calloc(1, sizeof(*pubkey)); if (!pubkey) goto err; /* Parse the PKCS #1 public key */ silc_buffer_set(&alg_key, key, key_len); if (!silc_asn1_decode(asn1, &alg_key, SILC_ASN1_OPTS(SILC_ASN1_ALLOC), SILC_ASN1_SEQUENCE, SILC_ASN1_INT(&pubkey->n), SILC_ASN1_INT(&pubkey->e), SILC_ASN1_END, SILC_ASN1_END)) goto err; /* Set key length */ pubkey->bits = ((silc_mp_sizeinbase(&pubkey->n, 2) + 7) / 8) * 8; silc_asn1_free(asn1); return key_len; err: silc_free(pubkey); silc_asn1_free(asn1); return 0; }
static void silc_pkcs_ssh_sign_cb(SilcBool success, const unsigned char *signature, SilcUInt32 signature_len, void *context) { SilcSshSign sign = context; SilcStack stack = sign->stack; unsigned char rbuf[20], sbuf[20]; SilcBufferStruct sig; SilcAsn1 asn1; SilcMPInt r, s; memset(&sig, 0, sizeof(sig)); /* Format the signature. RSA is easy because PKCS#1 is already in correct format. For DSA the returned signature is in PKIX compliant format and we have to reformat it for SSH2. */ if (!strcmp(sign->privkey->pkcs->name, "dsa")) { asn1 = silc_asn1_alloc(stack); if (!asn1) { sign->sign_cb(FALSE, NULL, 0, sign->context); silc_sfree(stack, sign); silc_stack_free(stack); return; } /* Decode the signature */ silc_buffer_set(&sig, (unsigned char *)signature, signature_len); if (!silc_asn1_decode(asn1, &sig, SILC_ASN1_SEQUENCE, SILC_ASN1_INT(&r), SILC_ASN1_INT(&s), SILC_ASN1_END, SILC_ASN1_END)) { sign->sign_cb(FALSE, NULL, 0, sign->context); silc_asn1_free(asn1); silc_sfree(stack, sign); silc_stack_free(stack); return; } /* Encode the integers */ memset(rbuf, 0, sizeof(rbuf)); memset(sbuf, 0, sizeof(sbuf)); silc_mp_mp2bin_noalloc(&r, rbuf, sizeof(rbuf)); silc_mp_mp2bin_noalloc(&s, sbuf, sizeof(sbuf)); silc_asn1_free(asn1); /* Encode SSH2 DSS signature */ if (silc_buffer_sformat(stack, &sig, SILC_STR_UI_INT(7), SILC_STR_UI32_STRING("ssh-dss"), SILC_STR_UI_INT(sizeof(rbuf) + sizeof(sbuf)), SILC_STR_DATA(rbuf, sizeof(rbuf)), SILC_STR_DATA(sbuf, sizeof(sbuf)), SILC_STR_END) < 0) { sign->sign_cb(FALSE, NULL, 0, sign->context); silc_sfree(stack, sign); silc_stack_free(stack); return; } } else { /* Encode SSH2 RSA signature */ if (silc_buffer_sformat(stack, &sig, SILC_STR_UI_INT(7), SILC_STR_UI32_STRING("ssh-rsa"), SILC_STR_UI_INT(signature_len), SILC_STR_DATA(signature, signature_len), SILC_STR_END) < 0) { sign->sign_cb(FALSE, NULL, 0, sign->context); silc_sfree(stack, sign); silc_stack_free(stack); return; } } /* Deliver result */ sign->sign_cb(TRUE, silc_buffer_data(&sig), silc_buffer_len(&sig), sign->context); silc_buffer_spurge(stack, &sig); silc_sfree(stack, sign); silc_stack_free(stack); }
SilcBool silc_pkcs1_verify(void *public_key, unsigned char *signature, SilcUInt32 signature_len, unsigned char *data, 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; }