bsafe_link.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2001-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if defined(BSAFE) || defined(DNSSAFE)
static const char rcsid[] = "$Header: /proj/cvs/isc/bind8/src/lib/dst/bsafe_link.c,v 1.15 2001/09/25 04:50:28 marka Exp $";
/*
* Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
*
* Permission to use, copy modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND TRUSTED INFORMATION SYSTEMS
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* TRUSTED INFORMATION SYSTEMS BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THE SOFTWARE.
*/
/*
* This file contains two components
* 1. Interface to the BSAFE library to allow compilation of Bind
* with TIS/DNSSEC when BSAFE is not available
* all calls to BSAFE are contained inside this file.
* 2. The glue to connvert RSA KEYS to and from external formats
*/
#include "port_before.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <sys/param.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include "dst_internal.h"
# ifdef __STDC__
# define PROTOTYPES 1
# else
# define PROTOTYPES 0
# endif
# ifdef BSAFE
# include <aglobal.h>
# include <bsafe.h>
# else
# include <global.h>
# include <bsafe2.h>
# include <bigmaxes.h>
# endif
#include "port_after.h"
typedef struct bsafekey {
char *rk_signer;
B_KEY_OBJ rk_Private_Key;
B_KEY_OBJ rk_Public_Key;
} RSA_Key;
#ifndef MAX_RSA_MODULUS_BITS
#define MAX_RSA_MODULUS_BITS 4096
#define MAX_RSA_MODULUS_LEN (MAX_RSA_MODULUS_BITS/8)
#define MAX_RSA_PRIME_LEN (MAX_RSA_MODULUS_LEN/2)
#endif
#define NULL_SURRENDER (A_SURRENDER_CTX *)NULL_PTR
#define NULL_RANDOM (B_ALGORITHM_OBJ)NULL_PTR
B_ALGORITHM_METHOD *CHOOSER[] =
{
&AM_MD5,
&AM_MD5_RANDOM,
&AM_RSA_KEY_GEN,
&AM_RSA_ENCRYPT,
&AM_RSA_DECRYPT,
&AM_RSA_CRT_ENCRYPT,
&AM_RSA_CRT_DECRYPT,
(B_ALGORITHM_METHOD *) NULL_PTR
};
static u_char pkcs1[] =
{
0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00,
0x04, 0x10
};
static int dst_bsafe_md5digest(const int mode, B_ALGORITHM_OBJ *digest_obj,
const u_char *data, const int len,
u_char *digest, const int digest_len);
static int dst_bsafe_key_size(RSA_Key *r_key);
static int dst_bsafe_sign(const int mode, DST_KEY *dkey, void **context,
const u_char *data, const int len,
u_char *signature, const int sig_len);
static int dst_bsafe_verify(const int mode, DST_KEY *dkey, void **context,
const u_char *data, const int len,
const u_char *signature, const int sig_len);
static int dst_bsafe_to_dns_key(const DST_KEY *in_key, u_char *out_str,
const int out_len);
static int dst_bsafe_from_dns_key(DST_KEY *s_key, const u_char *key,
const int len);
static int dst_bsafe_key_to_file_format(const DST_KEY *key, char *buff,
const int buff_len);
static int dst_bsafe_key_from_file_format(DST_KEY *d_key,
const char *buff,
const int buff_len);
static int dst_bsafe_generate_keypair(DST_KEY *key, int exp);
static int dst_bsafe_compare_keys(const DST_KEY *key1, const DST_KEY *key2);
static void *dst_bsafe_free_key_structure(void *key);
/*
* dst_bsafe_init() Function to answer set up function pointers for
* BSAFE/DNSSAFE related functions
*/
int
dst_bsafe_init(void)
{
if (dst_t_func[KEY_RSA] != NULL)
return (1);
dst_t_func[KEY_RSA] = malloc(sizeof(struct dst_func));
if (dst_t_func[KEY_RSA] == NULL)
return (0);
memset(dst_t_func[KEY_RSA], 0, sizeof(struct dst_func));
dst_t_func[KEY_RSA]->sign = dst_bsafe_sign;
dst_t_func[KEY_RSA]->verify = dst_bsafe_verify;
dst_t_func[KEY_RSA]->compare = dst_bsafe_compare_keys;
dst_t_func[KEY_RSA]->generate = dst_bsafe_generate_keypair;
dst_t_func[KEY_RSA]->destroy = dst_bsafe_free_key_structure;
dst_t_func[KEY_RSA]->from_dns_key = dst_bsafe_from_dns_key;
dst_t_func[KEY_RSA]->to_dns_key = dst_bsafe_to_dns_key;
dst_t_func[KEY_RSA]->from_file_fmt = dst_bsafe_key_from_file_format;
dst_t_func[KEY_RSA]->to_file_fmt = dst_bsafe_key_to_file_format;
return (1);
}
/*
* dst_bsafe_sign
* Call BSAFE signing functions to sign a block of data.
* There are three steps to signing, INIT (initialize structures),
* UPDATE (hash (more) data), FINAL (generate a signature). This
* routine performs one or more of these steps.
* Parameters
* mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
* dkey structure holds context for a sign done in multiple calls.
* context the context to use for this computation
* data data to be signed.
* len length in bytes of data.
* priv_key key to use for signing.
* signature location to store signature.
* sig_len size in bytes of signature field.
* returns
* N Success on SIG_MODE_FINAL = returns signature length in bytes
* 0 Success on SIG_MODE_INIT and UPDATE
* <0 Failure
*/
static int
dst_bsafe_sign(const int mode, DST_KEY *dkey, void **context,
const u_char *data, const int len,
u_char *signature, const int sig_len)
{
u_int sign_len = 0;
int status = 0;
B_ALGORITHM_OBJ *md5_ctx = NULL;
int w_bytes = 0;
u_int u_bytes = 0;
u_char work_area[NS_MD5RSA_MAX_SIZE];
if (mode & SIG_MODE_INIT) {
md5_ctx = (B_ALGORITHM_OBJ *) malloc(sizeof(B_ALGORITHM_OBJ));
if ((status = B_CreateAlgorithmObject(md5_ctx)))
return (-1);
if ((status = B_SetAlgorithmInfo(*md5_ctx, AI_MD5, NULL)))
return (-1);
}
else if (context)
md5_ctx = (B_ALGORITHM_OBJ *) *context;
if (md5_ctx == NULL)
return (-1);
w_bytes = dst_bsafe_md5digest(mode, md5_ctx,
data, len,work_area, sizeof(work_area));
if (w_bytes < 0 || (mode & SIG_MODE_FINAL)) {
B_DestroyAlgorithmObject(md5_ctx);
SAFE_FREE(md5_ctx);
if (w_bytes < 0)
return (w_bytes);
}
if (mode & SIG_MODE_FINAL) {
RSA_Key *key;
int ret = 0;
B_ALGORITHM_OBJ rsaEncryptor = (B_ALGORITHM_OBJ) NULL_PTR;
if (dkey == NULL || dkey->dk_KEY_struct == NULL)
return (-1);
key = (RSA_Key *) dkey->dk_KEY_struct;
if (key == NULL || key->rk_Private_Key == NULL)
return (-1);
if ((status = B_CreateAlgorithmObject(&rsaEncryptor)))
return (SIGN_FINAL_FAILURE);
if ((status = B_SetAlgorithmInfo(rsaEncryptor,
AI_PKCS_RSAPrivate,
NULL_PTR)))
ret = SIGN_FINAL_FAILURE;
if (ret == 0 &&
(status = B_EncryptInit(rsaEncryptor,
key->rk_Private_Key,
CHOOSER, NULL_SURRENDER)))
ret = SIGN_FINAL_FAILURE;
if (ret == 0 &&
(status = B_EncryptUpdate(rsaEncryptor, signature,
&u_bytes, sig_len, pkcs1,
sizeof(pkcs1), NULL_PTR,
NULL_SURRENDER)))
ret = SIGN_FINAL_FAILURE;
if (ret == 0 &&
(status = B_EncryptUpdate(rsaEncryptor, signature,
&u_bytes, sig_len, work_area,
w_bytes, NULL_PTR,
NULL_SURRENDER)))
ret = SIGN_FINAL_FAILURE;
if (ret == 0 &&
(status = B_EncryptFinal(rsaEncryptor, signature + u_bytes,
&sign_len, sig_len - u_bytes,
NULL_PTR, NULL_SURRENDER)))
ret = SIGN_FINAL_FAILURE;
B_DestroyAlgorithmObject(&rsaEncryptor);
if (ret != 0)
return (ret);
}
else {
if (context == NULL)
return (-1);
*context = (void *) md5_ctx;
}
return (sign_len);
}
/*
* Dst_bsafe_verify
* Calls BSAFE verification routines. There are three steps to
* verification, INIT (initialize structures), UPDATE (hash (more) data),
* FINAL (generate a signature). This routine performs one or more of
* these steps.
* Parameters
* mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
* dkey structure holds context for a verify done in multiple calls.
* context the context to use for this computation
* data data signed.
* len length in bytes of data.
* pub_key key to use for verify.
* signature signature.
* sig_len length in bytes of signature.
* returns
* 0 Success
* <0 Failure
*/
static int
dst_bsafe_verify(const int mode, DST_KEY *dkey, void **context,
const u_char *data, const int len,
const u_char *signature, const int sig_len)
{
B_ALGORITHM_OBJ *md5_ctx = NULL;
u_char digest[DST_HASH_SIZE];
u_char work_area[DST_HASH_SIZE + sizeof(pkcs1)];
int status = 0, w_bytes = 0;
u_int u_bytes = 0;
if (mode & SIG_MODE_INIT) {
md5_ctx = (B_ALGORITHM_OBJ *) malloc(sizeof(B_ALGORITHM_OBJ));
if ((status = B_CreateAlgorithmObject(md5_ctx)))
return (-1);
if ((status = B_SetAlgorithmInfo(*md5_ctx, AI_MD5, NULL)))
return (-1);
}
else if (context)
md5_ctx = (B_ALGORITHM_OBJ *) *context;
if (md5_ctx == NULL)
return (-1);
w_bytes = dst_bsafe_md5digest(mode, md5_ctx, data, len,
digest, sizeof(digest));
if (w_bytes < 0 || (mode & SIG_MODE_FINAL)) {
B_DestroyAlgorithmObject(md5_ctx);
SAFE_FREE(md5_ctx);
if (w_bytes < 0)
return (-1);
}
if (mode & SIG_MODE_FINAL) {
RSA_Key *key;
int ret = 0;
B_ALGORITHM_OBJ rsaEncryptor = (B_ALGORITHM_OBJ) NULL_PTR;
if (dkey == NULL || dkey->dk_KEY_struct == NULL)
return (-1);
key = (RSA_Key *) dkey->dk_KEY_struct;
if (key->rk_Public_Key == NULL)
return (-2);
if (rsaEncryptor == NULL_PTR) {
if ((status = B_CreateAlgorithmObject(&rsaEncryptor)))
ret = SIGN_FINAL_FAILURE;
if (ret == 0 &&
(status = B_SetAlgorithmInfo(rsaEncryptor,
AI_PKCS_RSAPublic,
NULL_PTR)))
ret = VERIFY_FINAL_FAILURE;
}
if (ret == 0 &&
(status = B_DecryptInit(rsaEncryptor, key->rk_Public_Key,
CHOOSER, NULL_SURRENDER)))
ret = VERIFY_FINAL_FAILURE;
if (ret == 0 &&
(status = B_DecryptUpdate(rsaEncryptor, work_area,
&u_bytes, 0,
(const u_char *) signature,
sig_len,
NULL_PTR, NULL_SURRENDER)))
ret = VERIFY_FINAL_FAILURE;
if (ret == 0 &&
(status = B_DecryptFinal(rsaEncryptor, work_area + u_bytes,
&u_bytes,
sizeof(work_area) - u_bytes,
NULL_PTR, NULL_SURRENDER)))
ret = VERIFY_FINAL_FAILURE;
B_DestroyAlgorithmObject(&rsaEncryptor);
/* skip PKCS#1 header in output from Decrypt function */
if (ret)
return (ret);
ret = memcmp(digest, &work_area[sizeof(pkcs1)], w_bytes);
if (ret == 0)
return(0);
else
return(VERIFY_FINAL_FAILURE);
}
else {
if (context == NULL)
return (-1);
*context = (void *) md5_ctx;
}
return (0);
}
/*
* dst_bsafe_to_dns_key
* Converts key from RSA to DNS distribution format
* This function gets in a pointer to the public key and a work area
* to write the key into.
* Parameters
* public KEY structure
* out_str buffer to write encoded key into
* out_len size of out_str
* Return
* N >= 0 length of encoded key
* n < 0 error
*/
static int
dst_bsafe_to_dns_key(const DST_KEY *in_key, u_char *out_str,
const int out_len)
{
B_KEY_OBJ public;
A_RSA_KEY *pub = NULL;
u_char *op = out_str;
int n = 0;
if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
out_len <= 0 || out_str == NULL)
return (-1);
public = (B_KEY_OBJ)((RSA_Key *) in_key->dk_KEY_struct)->rk_Public_Key;
n = B_GetKeyInfo((POINTER *) &pub, public, KI_RSAPublic);
if (n != 0)
return (-1);
if (pub->exponent.len < 256) { /* key exponent is <= 2040 bits */
if ((unsigned int)out_len < pub->exponent.len + 1)
return (-1);
*op++ = (u_int8_t) pub->exponent.len;
} else { /* key exponent is > 2040 bits */
u_int16_t e = (u_int16_t) pub->exponent.len;
if ((unsigned int)out_len < pub->exponent.len + 3)
return (-1);
*op++ = 0; /* 3 byte length field */
dst_s_put_int16(op, e);
op += sizeof(e);
n = 2;
}
n++;
memcpy(op, pub->exponent.data, pub->exponent.len);
op += pub->exponent.len;
n += pub->exponent.len;
if ((unsigned int)(out_len - n) >= pub->modulus.len) {
/*copy exponent */
memcpy(op, pub->modulus.data, pub->modulus.len);
n += pub->modulus.len;
}
else
n = -1;
return (n);
}
/*
* dst_bsafe_from_dns_key
* Converts from a DNS KEY RR format to an RSA KEY.
* Parameters
* len Length in bytes of DNS key
* key DNS key
* name Key name
* s_key DST structure that will point to the RSA key this routine
* will build.
* Return
* 0 The input key, s_key or name was null.
* 1 Success
*/
static int
dst_bsafe_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
{
int bytes;
const u_char *key_ptr;
RSA_Key *r_key;
A_RSA_KEY *public;
if (s_key == NULL || len < 0 || key == NULL)
return (0);
r_key = (RSA_Key *) s_key->dk_KEY_struct;
if (r_key != NULL) /* do not reuse */
s_key->dk_func->destroy(r_key);
if (len == 0)
return (1);
if ((r_key = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
EREPORT(("dst_bsafe_from_dns_key(): Memory allocation error 1"));
return (0);
}
memset(r_key, 0, sizeof(RSA_Key));
s_key->dk_KEY_struct = (void *) r_key;
r_key->rk_signer = strdup(s_key->dk_key_name);
if (B_CreateKeyObject(&r_key->rk_Public_Key) != 0) {
EREPORT(("dst_bsafe_from_dns_key(): Memory allocation error 3"));
s_key->dk_func->destroy(r_key);
return (0);
}
key_ptr = key;
bytes = (int) *key_ptr++; /* length of exponent in bytes */
if (bytes == 0) { /* special case for long exponents */
bytes = (int) dst_s_get_int16(key_ptr);
key_ptr += sizeof(u_int16_t);
}
if (bytes > MAX_RSA_MODULUS_LEN) {
dst_bsafe_free_key_structure(r_key);
return (-1);
}
if ((public = (A_RSA_KEY *) malloc(sizeof(A_RSA_KEY))) == NULL)
return (0);
memset(public, 0, sizeof(*public));
public->exponent.len = bytes;
if ((public->exponent.data = (u_char *) malloc(bytes)) == NULL)
return (0);
memcpy(public->exponent.data, key_ptr, bytes);
key_ptr += bytes; /* beginning of modulus */
bytes = len - bytes - 1; /* length of modulus */
if (bytes > MAX_RSA_MODULUS_LEN) {
dst_bsafe_free_key_structure(r_key);
return (-1);
}
public->modulus.len = bytes;
if ((public->modulus.data = (u_char *) malloc(bytes)) == NULL)
return (0);
memcpy(public->modulus.data, key_ptr, bytes);
B_SetKeyInfo(r_key->rk_Public_Key, KI_RSAPublic, (POINTER) public);
s_key->dk_key_size = dst_bsafe_key_size(r_key);
SAFE_FREE(public->modulus.data);
SAFE_FREE(public->exponent.data);
SAFE_FREE(public);
return (1);
}
/*
* dst_bsafe_key_to_file_format
* Encodes an RSA Key into the portable file format.
* Parameters
* rkey RSA KEY structure
* buff output buffer
* buff_len size of output buffer
* Return
* 0 Failure - null input rkey
* -1 Failure - not enough space in output area
* N Success - Length of data returned in buff
*/
static int
dst_bsafe_key_to_file_format(const DST_KEY *key, char *buff,
const int buff_len)
{
char *bp;
int len, b_len;
B_KEY_OBJ rkey;
A_PKCS_RSA_PRIVATE_KEY *private = NULL;
if (key == NULL || key->dk_KEY_struct == NULL) /* no output */
return (0);
if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
return (-1); /* no OR not enough space in output area */
rkey = (B_KEY_OBJ)((RSA_Key *) key->dk_KEY_struct)->rk_Private_Key;
B_GetKeyInfo((POINTER *) &private, rkey, KI_PKCS_RSAPrivate);
memset(buff, 0, buff_len); /* just in case */
/* write file header */
sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_RSA, "RSA");
bp = strchr(buff, '\0');
b_len = buff_len - (bp - buff);
if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Modulus: ",
private->modulus.data,
private->modulus.len)) <= 0)
return (-1);
bp += len;
b_len -= len;
if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PublicExponent: ",
private->publicExponent.data,
private->publicExponent.len)) <= 0)
return (-2);
bp += len;
b_len -= len;
if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PrivateExponent: ",
private->privateExponent.data,
private->privateExponent.len)) <= 0)
return (-3);
bp += len;
b_len -= len;
if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime1: ",
private->prime[0].data,
private->prime[0].len)) < 0)
return (-4);
bp += len;
b_len -= len;
if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime2: ",
private->prime[1].data,
private->prime[1].len)) < 0)
return (-5);
bp += len;
b_len -= len;
if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent1: ",
private->primeExponent[0].data,
private->primeExponent[0].len)) < 0)
return (-6);
bp += len;
b_len -= len;
if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent2: ",
private->primeExponent[1].data,
private->primeExponent[1].len)) < 0)
return (-7);
bp += len;
b_len -= len;
if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Coefficient: ",
private->coefficient.data,
private->coefficient.len)) < 0)
return (-8);
bp += len;
b_len -= len;
return (buff_len - b_len);
}
/*
* dst_bsafe_key_from_file_format
* Converts contents of a private key file into a private RSA key.
* Parameters
* RSA_Key structure to put key into
* buff buffer containing the encoded key
* buff_len the length of the buffer
* Return
* n >= 0 Foot print of the key converted
* n < 0 Error in conversion
*/
static int
dst_bsafe_key_from_file_format(DST_KEY *d_key, const char *buff,
const int buff_len)
{
int status;
char s[RAW_KEY_SIZE];
int len, s_len = sizeof(s);
const char *p = buff;
RSA_Key *b_key;
A_RSA_KEY *public;
A_PKCS_RSA_PRIVATE_KEY *private;
if (d_key == NULL || buff == NULL || buff_len <= 0)
return (-1);
b_key = (RSA_Key *) malloc(sizeof(RSA_Key));
public = (A_RSA_KEY *) malloc(sizeof(A_RSA_KEY));
private = (A_PKCS_RSA_PRIVATE_KEY *)
malloc(sizeof(A_PKCS_RSA_PRIVATE_KEY));
if (b_key == NULL || private == NULL || public == NULL) {
SAFE_FREE(b_key);
SAFE_FREE(public);
SAFE_FREE(private);
return (-2);
}
memset(b_key, 0, sizeof(*b_key));
memset(public, 0, sizeof(A_RSA_KEY));
memset(private, 0, sizeof(A_PKCS_RSA_PRIVATE_KEY));
d_key->dk_KEY_struct = (void *) b_key;
if (!dst_s_verify_str(&p, "Modulus: "))
return (-3);
memset(s, 0, s_len);
if ((len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)) == 0)
return (-4);
private->modulus.len = len;
if ((private->modulus.data = malloc(len)) == NULL)
return (-5);
memcpy(private->modulus.data, s + s_len - len, len);
while (*(++p) && p < (const char *) &buff[buff_len]) {
if (dst_s_verify_str(&p, "PublicExponent: ")) {
if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)))
return (-5);
private->publicExponent.len = len;
if ((private->publicExponent.data = malloc(len))
== NULL)
return (-6);
memcpy(private->publicExponent.data,
s + s_len - len, len);
} else if (dst_s_verify_str(&p, "PrivateExponent: ")) {
if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)))
return (-6);
private->privateExponent.len = len;
if ((private->privateExponent.data = malloc(len))
== NULL)
return (-7);
memcpy(private->privateExponent.data, s + s_len - len,
len);
} else if (dst_s_verify_str(&p, "Prime1: ")) {
if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
MAX_RSA_PRIME_LEN)))
return (-7);
private->prime[0].len = len;
if ((private->prime[0].data = malloc(len)) == NULL)
return (-8);
memcpy(private->prime[0].data,
s + MAX_RSA_PRIME_LEN - len, len);
} else if (dst_s_verify_str(&p, "Prime2: ")) {
if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
MAX_RSA_PRIME_LEN)))
return (-8);
private->prime[1].len = len;
if ((private->prime[1].data = malloc(len)) == NULL)
return (-9);
memcpy(private->prime[1].data,
s + MAX_RSA_PRIME_LEN - len, len);
} else if (dst_s_verify_str(&p, "Exponent1: ")) {
if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
MAX_RSA_PRIME_LEN)))
return (-9);
private->primeExponent[0].len = len;
if ((private->primeExponent[0].data = malloc(len))
== NULL)
return (-10);
memcpy(private->primeExponent[0].data,
s + MAX_RSA_PRIME_LEN - len, len);
} else if (dst_s_verify_str(&p, "Exponent2: ")) {
if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
MAX_RSA_PRIME_LEN)))
return (-10);
private->primeExponent[1].len = len;
if ((private->primeExponent[1].data = malloc(len))
== NULL)
return (-11);
memcpy(private->primeExponent[1].data,
s + MAX_RSA_PRIME_LEN - len, len);
} else if (dst_s_verify_str(&p, "Coefficient: ")) {
if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
MAX_RSA_PRIME_LEN)))
return (-11);
private->coefficient.len = len;
if ((private->coefficient.data = malloc(len)) == NULL)
return (-12);
memcpy(private->coefficient.data,
s + MAX_RSA_PRIME_LEN - len, len);
} else {
EREPORT(("Decode_RSAKey(): Bad keyword %s\n", p));
return (-12);
}
} /* while p */
public->modulus.len = private->modulus.len;
if ((public->modulus.data = (u_char *) malloc(public->modulus.len)) ==
NULL)
return (-13);
memcpy(public->modulus.data, private->modulus.data,
private->modulus.len);
public->exponent.len = private->publicExponent.len;
if ((public->exponent.data = (u_char *) malloc(public->exponent.len))
== NULL)
return (-14);
memcpy(public->exponent.data, private->publicExponent.data,
private->publicExponent.len);
status = B_CreateKeyObject(&(b_key->rk_Public_Key));
if (status)
return (-1);
status = B_SetKeyInfo(b_key->rk_Public_Key, KI_RSAPublic,
(POINTER) public);
if (status)
return (-1);
status = B_CreateKeyObject(&b_key->rk_Private_Key);
if (status)
return (-1);
status = B_SetKeyInfo(b_key->rk_Private_Key, KI_PKCS_RSAPrivate,
(POINTER) private);
if (status)
return (-1);
d_key->dk_key_size = dst_bsafe_key_size(b_key);
SAFE_FREE(private->modulus.data);
SAFE_FREE(private->publicExponent.data);
SAFE_FREE(private->privateExponent.data);
SAFE_FREE(private->prime[0].data);
SAFE_FREE(private->prime[1].data);
SAFE_FREE(private->primeExponent[0].data);
SAFE_FREE(private->primeExponent[1].data);
SAFE_FREE(private->coefficient.data);
SAFE_FREE(private); /* is this the right thing to do ??? XXXX */
SAFE_FREE(public->modulus.data);
SAFE_FREE(public->exponent.data);
SAFE_FREE(public);
return (0);
}
/*
* dst_bsafe_free_key_structure
* Frees all dynamicly allocated structures in RSA_Key.
*/
static void *
dst_bsafe_free_key_structure(void *key)
{
RSA_Key *r_key = (RSA_Key *) key;
if (r_key != NULL) {
if (r_key->rk_Private_Key)
B_DestroyKeyObject(&r_key->rk_Private_Key);
if (r_key->rk_Public_Key)
B_DestroyKeyObject(&r_key->rk_Public_Key);
SAFE_FREE2(r_key->rk_signer, strlen(r_key->rk_signer));
SAFE_FREE(r_key);
}
return (NULL);
}
/*
* dst_bsafe_generate_keypair
* Generates unique keys that are hard to predict.
* Parameters
* key generic Key structure
* exp the public exponent
* Return
* 0 Failure
* 1 Success
*/
static int
dst_bsafe_generate_keypair(DST_KEY *key, int exp)
{
int i, status;
B_KEY_OBJ private;
B_KEY_OBJ public;
B_ALGORITHM_OBJ keypairGenerator;
B_ALGORITHM_OBJ randomAlgorithm;
A_RSA_KEY_GEN_PARAMS keygenParams;
char exponent[4];
int exponent_len;
RSA_Key *rsa;
POINTER randomSeed = NULL_PTR;
int randomSeedLen;
A_RSA_KEY *pk_access = NULL;
if (key == NULL || key->dk_alg != KEY_RSA)
return (0);
if ((rsa = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
EREPORT(("dst_bsafe_generate_keypair: Memory allocation error 3"));
return (0);
}
memset(rsa, 0, sizeof(*rsa));
if ((status = B_CreateAlgorithmObject(&keypairGenerator)) != 0)
return (0);
keygenParams.modulusBits = key->dk_key_size;
/* exp = 0 or 1 are special (mean 3 or F4) */
if (exp == 0)
exp = 3;
else if (exp == 1)
exp = 65537;
/* Now encode the exponent and its length */
if (exp < 256) {
exponent_len = 1;
exponent[0] = exp;
} else if (exp < (1 << 16)) {
exponent_len = 2;
exponent[0] = exp >> 8;
exponent[1] = exp;
} else if (exp < (1 << 24)) {
exponent_len = 3;
exponent[0] = exp >> 16;
exponent[1] = exp >> 8;
exponent[2] = exp;
} else {
exponent_len = 4;
exponent[0] = exp >> 24;
exponent[1] = exp >> 16;
exponent[2] = exp >> 8;
exponent[3] = exp;
}
if ((keygenParams.publicExponent.data = (u_char *) malloc(exponent_len))
== NULL)
return (0);
memcpy(keygenParams.publicExponent.data, exponent, exponent_len);
keygenParams.publicExponent.len = exponent_len;
if ((status = B_SetAlgorithmInfo
(keypairGenerator, AI_RSAKeyGen, (POINTER) &keygenParams)) != 0)
return (0);
if ((status = B_GenerateInit(keypairGenerator, CHOOSER,
NULL_SURRENDER)) != 0)
return (0);
if ((status = B_CreateKeyObject(&public)) != 0)
return (0);
if ((status = B_CreateKeyObject(&private)) != 0)
return (0);
if ((status = B_CreateAlgorithmObject(&randomAlgorithm)) != 0)
return (0);
if ((status = B_SetAlgorithmInfo(randomAlgorithm, AI_MD5Random,
NULL_PTR))
!= 0)
return (0);
if ((status = B_RandomInit(randomAlgorithm, CHOOSER,
NULL_SURRENDER)) != 0)
return (0);
randomSeedLen = 256;
if ((randomSeed = malloc(randomSeedLen)) == NULL)
return (0);
if ((status = (randomSeed == NULL_PTR)) != 0)
return (0);
/* gets random seed from /dev/random if present, generates random
* values if it is not present.
* first fill the buffer with semi random data
* then fill as much as possible with good random data
*/
i = dst_random(DST_RAND_SEMI, randomSeedLen, randomSeed);
i += dst_random(DST_RAND_KEY, randomSeedLen, randomSeed);
if (i <= randomSeedLen) {
SAFE_FREE(rsa);
return(0);
}
if ((status = B_RandomUpdate(randomAlgorithm, randomSeed,
randomSeedLen, NULL_SURRENDER)) != 0) {
SAFE_FREE(rsa);
return (0);
}
SAFE_FREE2(randomSeed, randomSeedLen);
if ((status = B_GenerateKeypair(keypairGenerator, public, private,
randomAlgorithm, NULL_SURRENDER))
!= 0) {
SAFE_FREE(rsa);
return (0);
}
rsa->rk_signer = strdup(key->dk_key_name);
rsa->rk_Private_Key = private;
rsa->rk_Public_Key = public;
key->dk_KEY_struct = (void *) rsa;
B_GetKeyInfo((POINTER *) &pk_access, public, KI_RSAPublic);
return (1);
}
/**************************************************************************
* dst_bsafe_compare_keys
* Compare two keys for equality.
* Return
* 0 The keys are equal
* NON-ZERO The keys are not equal
*/
static int
dst_s_bsafe_itemcmp(ITEM i1, ITEM i2)
{
if (i1.len != i2.len || memcmp (i1.data, i2.data, i1.len))
return (1);
else
return (0);
}
static int
dst_bsafe_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
{
int status, s1 = 0, s2 = 0;
RSA_Key *rkey1 = (RSA_Key *) key1->dk_KEY_struct;
RSA_Key *rkey2 = (RSA_Key *) key2->dk_KEY_struct;
A_RSA_KEY *public1 = NULL, *public2 = NULL;
A_PKCS_RSA_PRIVATE_KEY *p1 = NULL, *p2 = NULL;
if (rkey1 == NULL && rkey2 == NULL)
return(0);
else if (rkey1 == NULL)
return (1);
else if (rkey2 == NULL)
return (2);
if (rkey1->rk_Public_Key)
B_GetKeyInfo((POINTER *) &public1, rkey1->rk_Public_Key,
KI_RSAPublic);
if (rkey2->rk_Public_Key)
B_GetKeyInfo((POINTER *) &public2, rkey2->rk_Public_Key,
KI_RSAPublic);
if (public1 == NULL && public2 == NULL)
return (0);
else if (public1 == NULL || public2 == NULL)
return (1);
status = dst_s_bsafe_itemcmp(public1->modulus, public2->modulus) ||
dst_s_bsafe_itemcmp(public1->exponent, public2->exponent);
if (status)
return (status);
if (rkey1->rk_Private_Key == NULL || rkey2->rk_Private_Key == NULL)
/* if neither or only one is private key consider identical */
return (status);
if (rkey1->rk_Private_Key)
s1 = B_GetKeyInfo((POINTER *) &p1, rkey1->rk_Private_Key,
KI_PKCS_RSAPrivate);
if (rkey2->rk_Private_Key)
s2 = B_GetKeyInfo((POINTER *) &p2, rkey2->rk_Private_Key,
KI_PKCS_RSAPrivate);
if (p1 == NULL || p2 == NULL)
return (0);
status = dst_s_bsafe_itemcmp(p1->modulus, p2->modulus) ||
dst_s_bsafe_itemcmp (p1->publicExponent,
p2->publicExponent) ||
dst_s_bsafe_itemcmp (p1->privateExponent,
p2->privateExponent) ||
dst_s_bsafe_itemcmp (p1->prime[0], p2->prime[0]) ||
dst_s_bsafe_itemcmp (p1->prime[1], p2->prime[1]) ||
dst_s_bsafe_itemcmp (p1->primeExponent[0],
p2->primeExponent[0])||
dst_s_bsafe_itemcmp (p1->primeExponent[1],
p2->primeExponent[1])||
dst_s_bsafe_itemcmp (p1->coefficient, p2->coefficient);
return (status);
}
/*
* dst_bsafe_key_size()
* Function to calculate how the size of the key in bits
*/
static int
dst_bsafe_key_size(RSA_Key *r_key)
{
int size;
A_PKCS_RSA_PRIVATE_KEY *private = NULL;
if (r_key == NULL)
return (-1);
if (r_key->rk_Private_Key)
B_GetKeyInfo((POINTER *) &private, r_key->rk_Private_Key,
KI_PKCS_RSAPrivate);
else if (r_key->rk_Public_Key)
B_GetKeyInfo((POINTER *) &private, r_key->rk_Public_Key,
KI_RSAPublic);
size = dst_s_calculate_bits(private->modulus.data,
private->modulus.len * 8);
return (size);
}
/*
* dst_bsafe_md5digest(): function to digest data using MD5 digest function
* if needed
*/
static int
dst_bsafe_md5digest(const int mode, B_ALGORITHM_OBJ *digest_obj,
const u_char *data, const int len,
u_char *digest, const int digest_len)
{
int status = 0;
u_int work_size = 0;
if (digest_obj == NULL || *digest_obj == NULL) {
printf("NO digest obj\n");
exit(33);
}
if ((mode & SIG_MODE_INIT) &&
(status = B_DigestInit(*digest_obj, (B_KEY_OBJ) NULL,
CHOOSER, NULL_SURRENDER)))
return (SIGN_INIT_FAILURE);
if ((mode & SIG_MODE_UPDATE) && data && (len > 0) &&
(status = B_DigestUpdate(*digest_obj, data, len, NULL_SURRENDER)))
return (SIGN_UPDATE_FAILURE);
if (mode & SIG_MODE_FINAL) {
if (digest == NULL ||
(status = B_DigestFinal(*digest_obj, digest, &work_size,
digest_len, NULL_SURRENDER)))
return (SIGN_FINAL_FAILURE);
return (work_size);
}
return (0);
}
/*
* just use the standard memory functions for bsafe
*/
void
T_free(POINTER block)
{
free(block);
}
POINTER
T_malloc(unsigned int len)
{
return (malloc(len));
}
int
T_memcmp(CPOINTER firstBlock, CPOINTER secondBlock, unsigned int len)
{
return (memcmp(firstBlock, secondBlock, len));
}
void
T_memcpy(POINTER output, CPOINTER input, unsigned int len)
{
memcpy(output, input, len);
}
void
T_memmove(POINTER output, POINTER input, unsigned int len)
{
memmove(output, input, len);
}
void
T_memset(POINTER output, int value, unsigned int len)
{
memset(output, value, len);
}
POINTER
T_realloc(POINTER block, unsigned int len)
{
return (realloc(block, len));
}
#else /* BSAFE NOT available */
int
dst_bsafe_init()
{
return (0);
}
#endif /* BSAFE */