diff options
Diffstat (limited to 'sbin/isakmpd/pkcs.c')
-rw-r--r-- | sbin/isakmpd/pkcs.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/sbin/isakmpd/pkcs.c b/sbin/isakmpd/pkcs.c new file mode 100644 index 00000000000..80f4aaf9349 --- /dev/null +++ b/sbin/isakmpd/pkcs.c @@ -0,0 +1,370 @@ +/* $OpenBSD: pkcs.c,v 1.4 1998/11/16 21:07:17 niklas Exp $ */ + +/* + * Copyright (c) 1998 Niels Provos. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ericsson Radio Systems. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This code was written under funding by Ericsson Radio Systems. + */ + +#include <sys/param.h> +#include <gmp.h> +#include <stdlib.h> +#include <string.h> + +#include "gmp_util.h" +#include "log.h" +#include "sysdep.h" +#include "asn.h" +#include "asn_useful.h" +#include "pkcs.h" + +struct norm_type RSAPublicKey[] = { + { TAG_INTEGER, UNIVERSAL, "modulus", 0, NULL}, /* modulus */ + { TAG_INTEGER, UNIVERSAL, "publicExponent", 0, NULL}, /* public exponent */ + { TAG_STOP, 0, NULL, 0, NULL} +}; + +struct norm_type RSAPrivateKey[] = { + { TAG_INTEGER, UNIVERSAL, "version", 1, "\0"}, /* version */ + { TAG_INTEGER, UNIVERSAL, "modulus", 0, NULL}, /* modulus */ + { TAG_INTEGER, UNIVERSAL, "publicExponent", 0, NULL}, /* public exponent */ + { TAG_INTEGER, UNIVERSAL, "privateExponent", 0, NULL},/* private exponent */ + { TAG_INTEGER, UNIVERSAL, "prime1", 0, NULL}, /* p */ + { TAG_INTEGER, UNIVERSAL, "prime2", 0, NULL}, /* q */ + { TAG_INTEGER, UNIVERSAL, "exponent1", 0, NULL}, /* d mod (p-1) */ + { TAG_INTEGER, UNIVERSAL, "exponent2", 0, NULL}, /* d mod (q-1) */ + { TAG_INTEGER, UNIVERSAL, "coefficient", 0, NULL}, /* inv. of q mod p */ + { TAG_STOP, 0, NULL, 0, NULL} +}; + +/* + * Fill in the data field in struct norm_type with the octet data + * from n. + */ + +int +pkcs_mpz_to_norm_type (struct norm_type *obj, mpz_ptr n) +{ + obj->len = sizeof (mpz_ptr); + if ((obj->data = malloc (obj->len)) == NULL) + return 0; + + mpz_init_set ((mpz_ptr) obj->data, n); + + return 1; +} + +/* + * Given the modulus and the public key, return an BER ASN.1 encoded + * PKCS#1 compliant RSAPublicKey object. + */ + +u_int8_t * +pkcs_public_key_to_asn (struct rsa_public_key *pub) +{ + u_int8_t *erg; + struct norm_type *key, seq = {TAG_SEQUENCE, UNIVERSAL, NULL, 0, NULL}; + + seq.data = &RSAPublicKey; + asn_template_clone (&seq, 1); + key = seq.data; + if (key == NULL) + return NULL; + + if (!pkcs_mpz_to_norm_type (&key[0], pub->n)) + { + free (key); + return NULL; + } + + if (!pkcs_mpz_to_norm_type (&key[1], pub->e)) + { + free (key[0].data); + free (key); + return NULL; + } + + erg = asn_encode_sequence (&seq, NULL); + + asn_free (&seq); + + return erg; +} + +/* + * Initalizes and Set's a Public Key Structure from an ASN BER encoded + * Public Key. + */ + +int +pkcs_public_key_from_asn (struct rsa_public_key *pub, u_int8_t *asn, + u_int32_t len) +{ + struct norm_type *key, seq = {TAG_SEQUENCE, UNIVERSAL, NULL, 0, NULL}; + + mpz_init (pub->n); + mpz_init (pub->e); + + seq.data = RSAPublicKey; + asn_template_clone (&seq, 1); + + if (seq.data == NULL) + return 0; + + if (asn_decode_sequence (asn, len, &seq) == NULL) + { + asn_free (&seq); + return 0; + } + + key = seq.data; + mpz_set (pub->n, (mpz_ptr) key[0].data); + mpz_set (pub->e, (mpz_ptr) key[1].data); + + asn_free (&seq); + + return 1; +} + +void +pkcs_free_public_key (struct rsa_public_key *pub) +{ + mpz_clear (pub->n); + mpz_clear (pub->e); +} + +/* + * Get ASN.1 representation of PrivateKey. + * XXX - not sure if we need this. + */ + +u_int8_t * +pkcs_private_key_to_asn (struct rsa_private_key *priv) +{ + mpz_t d1, d2, qinv; + struct norm_type *key, seq = {TAG_SEQUENCE, UNIVERSAL, NULL, 0, NULL}; + u_int8_t *erg = NULL; + + seq.data = RSAPrivateKey; + asn_template_clone (&seq, 1); + key = seq.data; + if (key == NULL) + return NULL; + + mpz_init (d1); + mpz_sub_ui (d1, priv->p, 1); + mpz_mod (d1, priv->d, d1); + + mpz_init (d2); + mpz_sub_ui (d2, priv->q, 1); + mpz_mod (d2, priv->d, d2); + + mpz_init (qinv); + mpz_invert (qinv, priv->q, priv->p); + + if (!pkcs_mpz_to_norm_type (&key[1], priv->n)) + goto done; + + if (!pkcs_mpz_to_norm_type (&key[2], priv->e)) + goto done; + + if (!pkcs_mpz_to_norm_type (&key[3], priv->d)) + goto done; + + if (!pkcs_mpz_to_norm_type (&key[4], priv->p)) + goto done; + + if (!pkcs_mpz_to_norm_type (&key[5], priv->q)) + goto done; + + if (!pkcs_mpz_to_norm_type (&key[6], d1)) + goto done; + + if (!pkcs_mpz_to_norm_type (&key[7], d2)) + goto done; + + if (!pkcs_mpz_to_norm_type (&key[8], qinv)) + goto done; + + mpz_set_ui (d1, 0); + + if (!pkcs_mpz_to_norm_type (&key[0], d1)) + goto done; + + erg = asn_encode_sequence (&seq, NULL); + + done: + asn_free (&seq); + + mpz_clear (d1); + mpz_clear (d2); + mpz_clear (qinv); + + return erg; +} + +/* + * Initalizes and Set's a Private Key Structure from an ASN BER encoded + * Private Key. + */ + +int +pkcs_private_key_from_asn (struct rsa_private_key *priv, u_int8_t *asn, + u_int32_t len) +{ + struct norm_type *key, seq = {TAG_SEQUENCE, UNIVERSAL, NULL, 0, NULL}; + u_int8_t *erg; + + mpz_init (priv->n); + mpz_init (priv->p); + mpz_init (priv->q); + mpz_init (priv->e); + mpz_init (priv->d); + + seq.data = RSAPrivateKey; + asn_template_clone (&seq, 1); + if (seq.data == NULL) + return 0; + + if (!(erg = asn_decode_sequence (asn, len, &seq))) + goto done; + + key = seq.data; + if (mpz_cmp_ui ((mpz_ptr) key[0].data, 0)) + { + log_print ("pkcs_set_private_key: version too high"); + erg = 0; + goto done; + } + + mpz_set (priv->n, key[1].data); + mpz_set (priv->e, key[2].data); + mpz_set (priv->d, key[3].data); + mpz_set (priv->p, key[4].data); + mpz_set (priv->q, key[5].data); + + done: + asn_free (&seq); + + return erg == NULL ? 0 : 1; +} + +void +pkcs_free_private_key (struct rsa_private_key *priv) +{ + mpz_clear (priv->n); + mpz_clear (priv->e); + mpz_clear (priv->d); + mpz_clear (priv->p); + mpz_clear (priv->q); +} + +/* + * Creates a PKCS#1 block with data and then uses the private + * exponent to do RSA encryption, returned is an allocated buffer + * with the encryption result. + * + * XXX CRIPPLED in the OpenBSD version as RSA is patented in the US. + */ +int +pkcs_rsa_encrypt (int art, mpz_ptr n, mpz_ptr e, u_int8_t *data, u_int32_t len, + u_int8_t **out, u_int32_t *outlen) +{ + /* XXX Always fail until we interface legal (in the US) RSA code. */ + return 0; +} + +/* + * Private Key Decryption, the 'in'-buffer is being destroyed + * + * XXX CRIPPLED in the OpenBSD version as RSA is patented in the US. + */ +int +pkcs_rsa_decrypt (int art, mpz_ptr n, mpz_ptr d, u_int8_t *in, + u_int8_t **out, u_int16_t *outlen) +{ + /* XXX Always fail until we interface legal (in the US) RSA code. */ + return 0; +} + +/* + * Generates a keypair suitable to be used for RSA. No checks are done + * on the generated key material. The following criteria might be + * enforced: p and q chosen randomly, |p-q| should be large, (p+1), (q+1), + * (p-1), (q-1) should have a large prime factor to be resistant e.g. + * against Pollard p-1 and Pollard p+1 factoring algorithms. + * For p-1 and q-1 the large prime factor itself - 1 should have a large + * prime factor. + * + * XXX CRIPPLED in the OpenBSD version as RSA is patented in the US. + */ +int +pkcs_generate_rsa_keypair (struct rsa_public_key *pubk, + struct rsa_private_key *seck, u_int32_t bits) +{ + /* XXX Always fail until we interface legal (in the US) RSA code. */ + return 0; +} + +/* Generate a random prime with at most bits significant bits */ + +int +pkcs_generate_prime (mpz_ptr p, u_int32_t bits) +{ + u_int32_t tmp, i; + + mpz_set_ui (p, 0); + i = tmp = 0; + while (bits > 0) + { + tmp = sysdep_random(); + + if (i++ == 0) + { + if (bits & 0x1f) + tmp &= (1 << (bits & 0x1f)) - 1; + tmp |= 1 << ((bits - 1) & 0x1f); + } + + mpz_mul_2exp (p, p, 32); + mpz_add_ui (p, p, tmp); + + bits -= (bits & 0x1f ? bits & 0x1f : 32); + } + + /* Make p odd */ + mpz_setbit (p, 0); + + /* Iterate as long as p is not a probable prime */ + while (!mpz_probab_prime_p (p, 50)) + mpz_add_ui (p, p, 2); + + return 1; +} |