diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1998-11-15 00:52:27 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1998-11-15 00:52:27 +0000 |
commit | 3188811a671a46dfde63d2145b9fc672861b573e (patch) | |
tree | 49cf89510a304d29909fb99bc089f24e3d7d70fa /sbin/isakmpd | |
parent | f69f398919124d8c650874dab35467927df84ecf (diff) |
Not clean enough yet
Diffstat (limited to 'sbin/isakmpd')
-rw-r--r-- | sbin/isakmpd/asn.c | 1155 | ||||
-rw-r--r-- | sbin/isakmpd/asn_useful.c | 128 | ||||
-rw-r--r-- | sbin/isakmpd/cert.c | 94 | ||||
-rw-r--r-- | sbin/isakmpd/x509.c | 844 |
4 files changed, 0 insertions, 2221 deletions
diff --git a/sbin/isakmpd/asn.c b/sbin/isakmpd/asn.c deleted file mode 100644 index 611579e3108..00000000000 --- a/sbin/isakmpd/asn.c +++ /dev/null @@ -1,1155 +0,0 @@ -/* $OpenBSD: asn.c,v 1.2 1998/11/15 00:43:49 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 <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <stdlib.h> -#include <string.h> -#include <gmp.h> -#include <unistd.h> - -#include "log.h" -#include "asn.h" -#include "gmp_util.h" - -struct asn_handler table[] = { - {TAG_INTEGER, asn_free_integer, - asn_get_encoded_len_integer, asn_decode_integer, asn_encode_integer}, - {TAG_OBJECTID, asn_free_objectid, - asn_get_encoded_len_objectid, asn_decode_objectid, asn_encode_objectid}, - {TAG_SEQUENCE, asn_free_sequence, - asn_get_encoded_len_sequence, asn_decode_sequence, asn_encode_sequence}, - {TAG_SET, asn_free_sequence, - asn_get_encoded_len_sequence, asn_decode_sequence, asn_encode_sequence}, - {TAG_UTCTIME, asn_free_string, - asn_get_encoded_len_string, asn_decode_string, asn_encode_string}, - {TAG_BITSTRING, asn_free_string, - asn_get_encoded_len_string, asn_decode_string, asn_encode_string}, - {TAG_OCTETSTRING, asn_free_string, - asn_get_encoded_len_string, asn_decode_string, asn_encode_string}, - {TAG_BOOL, asn_free_string, - asn_get_encoded_len_string, asn_decode_string, asn_encode_string}, - {TAG_PRINTSTRING, asn_free_string, - asn_get_encoded_len_string, asn_decode_string, asn_encode_string}, - {TAG_RAW, asn_free_raw, - asn_get_encoded_len_raw, asn_decode_raw, asn_encode_raw}, - {TAG_NULL, asn_free_null, - asn_get_encoded_len_null, asn_decode_null, asn_encode_null}, - {TAG_ANY, asn_free_null, - NULL, asn_decode_any, NULL}, - {TAG_STOP, NULL, NULL, NULL, NULL} -}; - -int -asn_get_from_file (char *name, u_int8_t **asn, u_int32_t *asnlen) -{ - int fd, res = 0; - struct stat st; - - if (stat (name, &st) == -1) - { - log_error ("asn_get_from_file: failed to state %s", name); - return 0; - } - - *asnlen = st.st_size; - - if ((fd = open (name, O_RDONLY)) == -1) - { - log_error ("asn_get_from_file: failed to open %s", name); - return 0; - } - - if ((*asn = malloc (st.st_size)) == NULL) - { - log_print ("asn_get_from_file: out of memory"); - res = 0; - goto done; - } - - if (read (fd, *asn, st.st_size) != st.st_size || - asn_get_len (*asn) != *asnlen) - { - log_print ("x509_asn_obtain: asn file ended early"); - free (*asn); - res = 0; - goto done; - } - - res = 1; - - done: - close (fd); - - return res; -} - -struct norm_type * -asn_template_clone (struct norm_type *obj, int constructed) -{ - struct norm_type *p; - u_int32_t i; - - if (!constructed) - { - p = malloc (sizeof (struct norm_type)); - if (p == NULL) - return NULL; - - memcpy (p, obj, sizeof (struct norm_type)); - - obj = p; - } - - if (obj->type != TAG_SEQUENCE && obj->type != TAG_SET) - { - obj->len = 0; - obj->data = NULL; - } - else if (obj->type == TAG_SEQUENCE || obj->type == TAG_SET) - { - p = obj; - obj = obj->data; - i = 0; - while (obj[i++].type != TAG_STOP); - - p->data = malloc (i * sizeof (struct norm_type)); - if (p->data == NULL) - return NULL; - - memcpy (p->data, obj, i * sizeof (struct norm_type)); - obj = p->data; - - i = 0; - while (obj[i].type != TAG_STOP) - { - obj[i].len = 0; - if (asn_template_clone (&obj[i], 1) == NULL) - return NULL; - - i++; - } - } - - return obj; -} - -/* Associates a human readable name to an OBJECT IDENTIFIER */ - -char * -asn_parse_objectid (struct asn_objectid *table, char *id) -{ - u_int32_t len = 0; - char *p = NULL; - static char buf[LINE_MAX]; - - if (id == NULL) - return NULL; - - while (table->name != NULL) - { - if (!strcmp (table->objectid, id)) - return table->name; - if (!strncmp (table->objectid, id, strlen (table->objectid)) && - strlen (table->objectid) > len) - { - len = strlen (table->objectid); - p = table->name; - } - - table++; - } - - if (len == 0) - return NULL; - - strncpy (buf, p, sizeof (buf) - 1); - buf[sizeof (buf) - 1] = 0; - strncat (buf + strlen (buf), id + len, sizeof (buf) -1 - strlen (buf)); - buf[sizeof (buf) - 1] = 0; - - return buf; -} - -/* Retrieves the pointer to a data type referenced by the path name */ - -struct norm_type * -asn_decompose (char *path, struct norm_type *obj) -{ - char *p, *p2, *tmp; - int counter; - - if (!strcasecmp (path, obj->name)) - return obj->data; - - p = path = strdup (path); - p2 = strsep (&p, "."); - - if (strcasecmp (p2, obj->name) || p == NULL) - goto fail; - - while (p != NULL) - { - obj = obj->data; - if (obj == NULL) - break; - - p2 = strsep (&p, "."); - - /* - * For SEQUENCE OF or SET OF, we want to be able to say - * AttributeValueAssertion[1] for the 2nd value. - */ - tmp = strchr (p2, '['); - if (tmp != NULL) - { - counter = atoi (tmp+1); - *tmp = 0; - } - else - counter = 0; - - /* Find the Tag */ - while (obj->type != TAG_STOP) - { - if (!strcasecmp (p2, obj->name) && counter-- == 0) - break; - obj++; - } - - if (obj->type == TAG_STOP) - goto fail; - - if (p == NULL) - goto done; - - if (obj->type != TAG_SEQUENCE && obj->type != TAG_SET) - goto fail; - } - - done: - free (path); - return obj; - - fail: - free (path); - return NULL; -} - -/* Gets an entry from the ASN.1 tag switch table */ - -struct asn_handler * -asn_get (enum asn_tags type) -{ - struct asn_handler *h = table; - - while (h->type != TAG_STOP) - if (h->type == type) - return h; - else - h++; - - return NULL; -} - -/* - * For the long form of BER encoding we need to know in how many - * octets the length can be encoded. - */ - -u_int32_t -asn_sizeinoctets (u_int32_t len) -{ - u_int32_t log = 0; - - while (len) - { - log++; - len >>= 8; - } - - return log; -} - -u_int8_t * -asn_format_header (struct norm_type *obj, u_int8_t *asn, u_int8_t **data) -{ - u_int8_t *buf = NULL, type; - u_int16_t len_off, len; - struct asn_handler *h; - - h = asn_get (obj->type); - if (h == NULL) - return NULL; - - if (asn != NULL) - buf = asn; - - /* We only do low tag at the moment */ - len_off = 1; - - len = h->get_encoded_len (obj, &type); - - if (buf == NULL && (buf = malloc (len)) == NULL) - return NULL; - - if (type != ASN_LONG_FORM) - { - len -= len_off + 1; - buf[len_off] = len; - - *data = buf + len_off + 1; - } - else - { - u_int16_t tmp; - int octets = asn_sizeinoctets (len); - - len -= len_off + 1 + octets; - *data = buf + len_off + 1 + octets; - - buf[len_off] = octets | ASN_LONG_FORM; - - tmp = len; - while (--octets >= 0) - { - buf[len_off + 1 + octets] = tmp; - tmp >>= 8; - } - } - - if (ISEXPLICIT(obj)) - { - u_int8_t *erg; - /* Explicit tagging add an outer layer */ - struct norm_type tmp = {obj->type, obj->class&0x3, NULL, 0, obj->data}; - - /* XXX - force the class to be CONTEXT */ - buf[0] = GET_EXP(obj) | (((enum asn_classes)CONTEXT & 0x3) << 6) | - ASN_CONSTRUCTED; - erg = asn_format_header (&tmp, *data, data); - - if (erg && (obj->type == TAG_SEQUENCE || obj->type == TAG_SET)) - erg[0] |= ASN_CONSTRUCTED; - } - else - /* XXX low tag only */ - buf[0] = obj->type | (obj->class << 6); - - return buf; -} - -u_int32_t -asn_get_encoded_len (struct norm_type *obj, u_int32_t len, u_int8_t *type) -{ - u_int32_t len_off = 1; - - if (len <= 127) - { - /* Short form */ - len = len + 1 + len_off; - if (type != NULL) - *type = 0; - } - else - { - /* Long Form */ - len = len + asn_sizeinoctets (len) + 1 + len_off; - if (type != NULL) - *type = ASN_LONG_FORM; - } - - if (obj != NULL && ISEXPLICIT(obj)) - len = asn_get_encoded_len (NULL, len, NULL); - - return len; -} - -/* Tries to decode an ANY tag, if we cant handle it we just raw encode it */ - -u_int8_t * -asn_decode_any (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj) -{ - struct asn_handler *h; - enum asn_tags type; - - type = TAG_TYPE (asn); - if (type == TAG_SEQUENCE || type == TAG_SET) - type = TAG_RAW; - - h = asn_get (type); - if (h == NULL) - { - type = TAG_RAW; - h = asn_get (type); - } - - obj->type = type; - return h->decode (asn, asnlen, obj); -} - -u_int32_t -asn_get_encoded_len_integer (struct norm_type *obj, u_int8_t *type) -{ - u_int16_t len_off; - u_int32_t len = obj->len; - u_int32_t tmp; - mpz_t a; - - /* XXX - We only do low tag at the moment */ - len_off = 1; - - obj->len = len = mpz_sizeinoctets ((mpz_ptr) obj->data); - mpz_init_set (a, (mpz_ptr) obj->data); - - if (len > 1) - mpz_fdiv_q_2exp (a, a, (len - 1) << 3); - - tmp = mpz_fdiv_r_ui (a, a, 256); - mpz_clear (a); - - /* - * We only need to encode positive integers, ASN.1 defines - * negative integers to have the msb set, so if data[0] has - * msb set we need to introduce a zero octet. - */ - if (tmp & 0x80) - len++; - - return asn_get_encoded_len (obj, len, type); -} - -/* - * Encode an integer value. - * Input = obj, output = asn or return value. - */ - -u_int8_t * -asn_encode_integer (struct norm_type *obj, u_int8_t *asn) -{ - u_int8_t *buf, *data; - u_int32_t len; - - buf = asn_format_header (obj, asn, &data); - - if (buf == NULL) - return NULL; - - len = mpz_sizeinoctets ((mpz_ptr) obj->data); - mpz_getraw (data, (mpz_ptr) obj->data, len); - - /* XXX - We only deal with unsigned integers at the moment */ - if (data[0] & 0x80) - { - memmove (data + 1, data, len); - data[0] = 0; - } - - return buf; -} - -u_int8_t * -asn_decode_integer (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj) -{ - u_int8_t *data; - u_int32_t len; - - if (asnlen < asn_get_len (asn)) - { - log_print ("asn_decode_integer: ASN.1 content is bigger than buffer"); - return NULL; - } - - len = asn_get_data_len (obj, &asn, &data); - - if (TAG_TYPE(asn) != TAG_INTEGER) - { - log_print ("asn_decode_integer: expected tag type INTEGER, got %d", - TAG_TYPE(asn)); - return NULL; - } - - obj->data = malloc (sizeof (mpz_ptr)); - if (obj->data == NULL) - { - log_print ("asn_decode_integer: out of memory."); - return NULL; - } - - mpz_init ((mpz_ptr) obj->data); - mpz_setraw ((mpz_ptr) obj->data, data, len); - - obj->len = len; - - return data + len; -} - -void -asn_free_integer (struct norm_type *obj) -{ - if (obj->data != NULL) - { - mpz_clear ((mpz_ptr) obj->data); - free (obj->data); - } -} - - -u_int32_t -asn_get_encoded_len_string (struct norm_type *obj, u_int8_t *type) -{ - return asn_get_encoded_len (obj, obj->len, type); -} - -/* - * Encode a String - * Input = obj, output = asn or return value. - */ - -u_int8_t * -asn_encode_string (struct norm_type *obj, u_int8_t *asn) -{ - u_int8_t *buf, *data; - - buf = asn_format_header (obj, asn, &data); - - if (buf == NULL) - return NULL; - - memcpy (data, obj->data, obj->len); - - return buf; -} - -u_int8_t * -asn_decode_string (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj) -{ - u_int8_t *data; - u_int32_t len; - - obj->len = len = asn_get_data_len (obj, &asn, &data); - - if (TAG_TYPE(asn) != obj->type) - { - log_print ("asn_decode_string: expected tag type STRING(%d), got %d", - obj->type, TAG_TYPE(asn)); - return NULL; - } - - if (asnlen < asn_get_len (asn)) - { - log_print ("asn_decode_string: ASN.1 content is bigger than buffer"); - return NULL; - } - - obj->data = malloc (obj->len + 1); - if (obj->data == NULL) - return NULL; - memcpy ((char *)obj->data, data, obj->len); - /* - * Encode a terminating '0', this is irrelevant for OCTET strings - * but nice for printable strings which do not include the terminating - * zero. - */ - ((char *)obj->data)[obj->len] = 0; - - return data + len; -} - -void -asn_free_string (struct norm_type *obj) -{ - if (obj->data != NULL) - free (obj->data); -} - - -u_int32_t -asn_get_encoded_len_objectid (struct norm_type *obj, u_int8_t *type) -{ - u_int16_t len_off; - u_int32_t len; - u_int32_t tmp; - char *buf, *buf2; - - /* XXX - We only do low tag at the moment */ - len_off = 1; - - /* The first two numbers are encoded together */ - buf = obj->data; - tmp = strtol (buf, &buf2, 10); - buf = buf2; - tmp = strtol (buf, &buf2, 10); - buf = buf2; - - len = 1; - while (*buf) - { - tmp = strtol (buf, &buf2, 10); - if (buf == buf2) - break; - - buf = buf2; - do { - tmp >>= 7; - len++; - } while (tmp); - } - - /* The first two ids are encoded as one octet */ - obj->len = len - 1; - - return asn_get_encoded_len (obj, len, type); -} - -/* - * Encode an Object Identifier - * Input = obj, output = asn or return value. - */ - -u_int8_t * -asn_encode_objectid (struct norm_type *obj, u_int8_t *asn) -{ - u_int8_t *buf, *data; - char *enc, *enc2; - u_int32_t tmp, tmp2; - int flag = 0; - - buf = asn_format_header (obj, asn, &data); - - if (buf == NULL) - return NULL; - - enc = obj->data; - while (*enc) - { - /* First two ids are encoded as one octet */ - if (flag == 0) - { - tmp = strtol (enc, &enc2, 10); - if (enc == enc2) - return NULL; - enc = enc2; - tmp2 = strtol (enc, &enc2, 10) + 40 * tmp; - flag = 1; - } - else - tmp2 = strtol (enc, &enc2, 10); - - if (enc == enc2) - break; - - /* Reverse the digits to base-128 */ - tmp = 0; - do { - tmp <<= 7; - tmp += tmp2 & 0x7f; - tmp2 >>= 7; - } while (tmp2); - - enc = enc2; - do { - /* If the next octet still belongs to the data set msb */ - *data++ = (tmp & 0x7f) | ( tmp > 127 ? 0x80 : 0); - tmp >>= 7; - } while (tmp); - } - - return buf; -} - -u_int8_t * -asn_decode_objectid (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj) -{ - u_int8_t *data; - u_int32_t len, c, tmp; - int flag = 0; - void *new_buf; - - len = asn_get_data_len (obj, &asn, &data); - - if (TAG_TYPE(asn) != TAG_OBJECTID) - { - log_print ("asn_decode_objectid: expected tag type OBJECTID, got %d", - TAG_TYPE(asn)); - return NULL; - } - - if (asnlen < asn_get_len (asn)) - { - log_print ("asn_decode_objectid: ASN.1 content is bigger than buffer"); - return NULL; - } - - obj->data = NULL; - obj->len = 0; - while (len > 0) - { - tmp = 0; - do { - tmp <<= 7; - tmp += *data & 0x7f; - } while (len-- > 0 && (*data++ & 0x80)); - - if (flag == 0) - c = snprintf (NULL, 0, "%d %d ", tmp/40, tmp % 40) + 1; - else - c = snprintf (NULL, 0, "%d ", tmp) + 1; - - new_buf = realloc (obj->data, obj->len + c); - if (new_buf == NULL) - { - free (obj->data); - obj->data = NULL; - log_print ("asn_decode_objectid: out of memory."); - return NULL; - } - obj->data = new_buf; - - if (flag == 0) - { - sprintf (obj->data + obj->len, "%d %d ", tmp/40, tmp % 40); - flag = 1; - } - else - sprintf (obj->data + obj->len, "%d ", tmp); - - obj->len = strlen (obj->data); - } - - if (obj->data != NULL) - ((char *)obj->data)[obj->len - 1] = 0; - - return data; -} - -void -asn_free_objectid (struct norm_type *obj) -{ - if (obj->data != NULL) - free (obj->data); -} - - -u_int32_t -asn_get_encoded_len_raw (struct norm_type *obj, u_int8_t *type) -{ - if (type != NULL) - { - if (obj->len > 127) - *type = ASN_LONG_FORM; - else - *type = 0; - } - - return obj->len; -} - -u_int8_t * -asn_encode_raw (struct norm_type *obj, u_int8_t *asn) -{ - u_int8_t *buf = NULL; - - if (obj->len == 0) - return asn; - - if (asn != NULL) - buf = asn; - - if (buf == NULL && (buf = malloc (obj->len)) == NULL) - return NULL; - - memcpy (buf, obj->data, obj->len); - - return buf; -} - -u_int8_t * -asn_decode_raw (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj) -{ - obj->len = asn_get_len (asn); - if (asnlen < obj->len) - { - log_print ("asn_decode_raw: ASN.1 content is bigger than buffer"); - return NULL; - } - - obj->data = malloc (obj->len); - if (obj->data == NULL) - { - log_print ("asn_decode_raw: out of memory"); - return NULL; - } - - memcpy (obj->data, asn, obj->len); - - return asn + obj->len; -} - -void -asn_free_raw (struct norm_type *obj) -{ - if (obj->data != NULL) - free (obj->data); -} - -u_int32_t -asn_get_encoded_len_null (struct norm_type *obj, u_int8_t *type) -{ - return asn_get_encoded_len (obj, 0, type); -} - -u_int8_t * -asn_encode_null (struct norm_type *obj, u_int8_t *asn) -{ - u_int8_t *buf = NULL; - - if (asn != NULL) - buf = asn; - - if (buf == NULL && (buf = malloc (2)) == NULL) - return NULL; - - buf[0] = obj->type; - buf[1] = 0; - - return buf; -} - -u_int8_t * -asn_decode_null (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj) -{ - obj->data = NULL; - obj->len = 0; - - return asn + asn_get_len (asn); -} - -void -asn_free_null (struct norm_type *obj) -{ - obj->data = NULL; -} - -void -asn_free (struct norm_type *obj) -{ - struct asn_handler *h = asn_get (obj->type); - - if (h == NULL) - log_print ("asn_free: unkown ASN.1 type %d", obj->type); - else - h->free (obj); -} - -/* - * Returns the whole length of the BER encoded ASN.1 object. - */ - -u_int32_t -asn_get_len (u_int8_t *asn) -{ - u_int32_t len; - u_int8_t *data; - struct norm_type tmp = {TAG_RAW, UNIVERSAL, NULL, 0, NULL}; - - len = asn_get_data_len (&tmp, &asn, &data); - - if (asn == NULL) - return 0; - - return (data - asn) + len; -} - -/* - * Returns the length of the ASN content, and a pointer to the content - * data itself. - * For TAG_NULL the data length is zero, so we have to return an error - * in asn, asn will be NULL in case of error. - */ - -u_int32_t -asn_get_data_len (struct norm_type *obj, u_int8_t **asn, u_int8_t **data) -{ - u_int32_t len; - u_int16_t len_off = 1; - - if (obj != NULL && ISEXPLICIT(obj)) - { - struct norm_type tmp = {TAG_RAW, UNIVERSAL, NULL, 0, NULL}; - - if (TAG_TYPE(*asn) != GET_EXP(obj)) - { - log_print ("asn_get_data_len: explict tagging was needed"); - *asn = NULL; - return 0; - } - - asn_get_data_len (&tmp, asn, data); - *asn = *data; - } - - if ((*asn)[len_off] & ASN_LONG_FORM) - { - int i, octets = (*asn)[len_off] & 0x7f; - - /* XXX - we only decode really small length */ - if (octets > sizeof (len)) - { - log_print ("asn_get_data_len: long form length %d exceeds " - "allowed maximum", octets); - *asn = NULL; - return 0; - } - - for (len = 0, i = 0; i < octets; i++) - { - len = (len << 8) | (*asn)[len_off + 1 + i]; - } - - if (data != NULL) - *data = *asn + len_off + 1 + octets; - } - else - { - /* Short form */ - len = (*asn)[len_off]; - - if (data != NULL) - *data = *asn + len_off + 1; - } - - return len; -} - -void -asn_free_sequence (struct norm_type *obj) -{ - struct norm_type *in = obj->data; - struct asn_handler *h; - - if (in == NULL) - return; - - while (in->type != TAG_STOP) - { - h = asn_get (in->type); - if (h == NULL) - break; - - h->free (in++); - } - - free (obj->data); -} - -u_int32_t -asn_get_encoded_len_sequence (struct norm_type *seq, u_int8_t *type) -{ - u_int32_t len, i; - struct asn_handler *h; - struct norm_type *obj = (struct norm_type *) seq->data; - - /* Get whole data length */ - for (len = 0, i = 0; obj[i].type != TAG_STOP; i++) - { - h = asn_get (obj[i].type); - if (h == NULL) - { - log_print ("asn_encode_sequence: unkown type %d", obj[i].type); - break; - } - len += h->get_encoded_len (&obj[i], NULL); - } - - return asn_get_encoded_len (seq, len, type); -} - -u_int8_t * -asn_encode_sequence (struct norm_type *seq, u_int8_t *asn) -{ - u_int32_t len; - u_int8_t *erg, *data; - struct norm_type *obj; - struct asn_handler *h; - int i; - - if ((h = asn_get (seq->type)) == NULL) - return NULL; - - obj = (struct norm_type *) seq->data; - - erg = asn_format_header (seq, asn, &data); - if (erg == NULL) - return NULL; - - for (i = 0, len = 0; obj[i].type != TAG_STOP; i++) - { - h = asn_get (obj[i].type); - if (h == NULL) - { - log_print ("asn_encode_sequence: unknown ASN.1 tag %d", obj[i].type); - return NULL; - } - - /* A structure can be optional, indicated by data == NULL */ - if (h->encode (&obj[i], data + len) == NULL && obj->data != NULL) - { - log_print ("asn_encode_sequence: encoding of %s failed", - obj[i].name); - return NULL; - } - len += h->get_encoded_len (&obj[i], NULL); - } - - erg[0] |= ASN_CONSTRUCTED; - - return erg; -} - -u_int8_t * -asn_decode_sequence (u_int8_t *asn, u_int32_t asnlen, struct norm_type *obj) -{ - u_int8_t *p, *data; - u_int32_t len, flags, objects; - struct asn_handler *h; - void *new_buf; - - if (asnlen < asn_get_len (asn)) - { - log_print ("asn_decode_sequence: ASN.1 content is bigger than buffer"); - return NULL; - } - - len = asn_get_data_len (obj, &asn, &data); - - /* XXX - an empty sequence is that okay */ - if (len == 0) - return data; - - if (TAG_TYPE(asn) != obj->type) - { - log_print ("asn_decode_sequence: expected tag type SEQUENCE/SET, got %d", - TAG_TYPE(asn)); - return NULL; - } - - /* Handle dynamic sized sets and sequences */ - flags = obj->flags; - - if (flags & ASN_FLAG_ZEROORMORE) - { - struct norm_type stop_tag = {TAG_STOP}; - struct norm_type *tmp; - - /* Zero occurences */ - if (len == 0) - { - asn_free (obj); - obj->data = NULL; - return data; - } - - /* Count number of objects */ - p = data; - objects = 0; - while (p < data + len) - { - objects++; - p += asn_get_len (p); - } - if (p != data + len) - { - log_print ("asn_decode_sequence: SEQ/SET OF too many elements"); - return NULL; - } - - /* - * Create new templates for dynamically added objects, - * the ASN.1 tags SEQUENCE OF and SET OF, specify an unknown - * number of elements. - */ - - new_buf = realloc (obj->data, - (objects+1) * sizeof (struct norm_type)); - if (new_buf == NULL) - { - asn_free (obj); - obj->data = NULL; - log_print ("asn_decode_sequence: out of memory"); - return NULL; - } - obj->data = new_buf; - - tmp = obj->data; - - /* Copy TAG_STOP */ - memcpy (tmp + objects, &stop_tag, sizeof (struct norm_type)); - while (objects-- > 1) - { - memcpy (tmp + objects, tmp, sizeof (struct norm_type)); - if (asn_template_clone (tmp + objects, 1) == NULL) - return NULL; - } - } - - obj = (struct norm_type *) obj->data; - - p = data; - while (p < data + len) - { - if (obj->type == TAG_STOP) - break; - h = asn_get (obj->type); - if (h == NULL) - { - log_print ("asn_decode_sequence: unknown ASN.1 tag %d", obj->type); - return NULL; - } - - if ((p = h->decode (p, (data - p) + len, obj++)) == NULL) - break; - } - - if (p < data + len) - log_print ("asn_decode_sequence: ASN tag was not decoded completely"); - - if (p == NULL) - return NULL; - - return data + len; -} diff --git a/sbin/isakmpd/asn_useful.c b/sbin/isakmpd/asn_useful.c deleted file mode 100644 index 1ec652d1b85..00000000000 --- a/sbin/isakmpd/asn_useful.c +++ /dev/null @@ -1,128 +0,0 @@ -/* $OpenBSD: asn_useful.c,v 1.2 1998/11/15 00:43:49 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 "asn.h" -#include "asn_useful.h" - -struct norm_type AlgorithmIdentifier[] = { - {TAG_OBJECTID, UNIVERSAL, "algorithm", 0, NULL}, - {TAG_ANY, UNIVERSAL, "parameters", 0, NULL}, - {TAG_STOP, UNIVERSAL, NULL, 0, NULL}}; - -struct norm_type Signed[] = { - {TAG_RAW, UNIVERSAL, "data", 0, NULL}, - SEQ("algorithm", AlgorithmIdentifier), - {TAG_BITSTRING, UNIVERSAL, "encrypted", 0, NULL}, - {TAG_STOP, UNIVERSAL, NULL, 0, NULL}}; - -struct norm_type Validity[] = { - {TAG_UTCTIME, UNIVERSAL, "notBefore", 0, NULL}, - {TAG_UTCTIME, UNIVERSAL, "notAfter", 0, NULL}, - {TAG_STOP, UNIVERSAL, NULL, 0, NULL}}; - -struct norm_type AttributeValueAssertion[] = { - {TAG_OBJECTID, UNIVERSAL, "AttributeType", 0, NULL}, - {TAG_ANY, UNIVERSAL, "AttributeValue", 0, NULL}, - {TAG_STOP, UNIVERSAL, NULL, 0, NULL}}; - -struct norm_type RelativeDistinguishedName[] = { - SEQ ("AttributeValueAssertion", AttributeValueAssertion), - {TAG_STOP}}; - -/* - * For decoding this structure is dynamically resized, we add two Names - * only for encoding purposes. - */ -struct norm_type RDNSequence[] = { - SETOF ("RelativeDistinguishedName", RelativeDistinguishedName), - SETOF ("RelativeDistinguishedName", RelativeDistinguishedName), - {TAG_STOP}}; - -struct norm_type SubjectPublicKeyInfo[] = { - SEQ ("algorithm", AlgorithmIdentifier), - {TAG_BITSTRING, UNIVERSAL, "subjectPublicKey", 0, NULL}, - {TAG_STOP}}; - -struct norm_type Extension[] = { - {TAG_OBJECTID, UNIVERSAL, "extnId", 0, NULL}, - {TAG_BOOL, UNIVERSAL, "critical", 0, NULL}, - {TAG_OCTETSTRING, UNIVERSAL, "extnValue", 0, NULL}, - {TAG_STOP}}; - -struct norm_type Extensions[] = { - SEQ ("extension", Extension), - {TAG_STOP}}; - -struct norm_type Certificate[] = { - /* We need to add an explicit tag, HACK XXX */ - {TAG_INTEGER, ADD_EXP(0, UNIVERSAL), "version", 0, NULL}, - {TAG_INTEGER, UNIVERSAL, "serialNumber", 0, NULL}, - SEQ ("signature", AlgorithmIdentifier), - SEQOF ("issuer", RDNSequence), - SEQ ("validity", Validity), - SEQOF ("subject", RDNSequence), - SEQ ("subjectPublicKeyInfo", SubjectPublicKeyInfo), - {TAG_RAW, UNIVERSAL, "extension", 0, NULL}, - {TAG_STOP}}; - -struct norm_type DigestInfo[] = { - SEQ ("digestAlgorithm", AlgorithmIdentifier), - {TAG_OCTETSTRING, UNIVERSAL, "digest", 0, NULL}, - {TAG_STOP}}; - -struct asn_objectid asn_ids[] = { - {"AttributeType", ASN_ID_ATTRIBUTE_TYPE}, - {"CountryName", ASN_ID_COUNTRY_NAME}, - {"LocalityName", ASN_ID_LOCALITY_NAME}, - {"StateOrProvinceName", ASN_ID_STATE_NAME}, - {"OrganizationName", ASN_ID_ORGANIZATION_NAME}, - {"OrganizationUnitName", ASN_ID_ORGUNIT_NAME}, - {"CommonUnitName", ASN_ID_COMMONUNIT_NAME}, - {"pkcs-1", ASN_ID_PKCS}, - {"rsaEncryption", ASN_ID_RSAENCRYPTION}, - {"md2WithRSAEncryption", ASN_ID_MD2WITHRSAENC}, - {"md4WithRSAEncryption", ASN_ID_MD4WITHRSAENC}, - {"md5WithRSAEncryption", ASN_ID_MD5WITHRSAENC}, - {"md2", ASN_ID_MD2}, - {"md4", ASN_ID_MD4}, - {"md5", ASN_ID_MD5}, - {"emailAddress", ASN_ID_EMAILADDRESS}, - {"id-ce", ASN_ID_CE}, - {"subjectAltName", ASN_ID_SUBJECT_ALT_NAME}, - {"issuerAltName", ASN_ID_ISSUER_ALT_NAME}, - {"basicConstraints", ASN_ID_BASIC_CONSTRAINTS}, - {NULL, NULL} }; diff --git a/sbin/isakmpd/cert.c b/sbin/isakmpd/cert.c deleted file mode 100644 index 9e53ec25795..00000000000 --- a/sbin/isakmpd/cert.c +++ /dev/null @@ -1,94 +0,0 @@ -/* $OpenBSD: cert.c,v 1.2 1998/11/15 00:43:50 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 <stdlib.h> -#include <string.h> - -#include "cert.h" -#include "isakmp_num.h" -#include "x509.h" - -struct cert_handler cert_handler[] = { - {ISAKMP_CERTENC_X509_SIG, - x509_certreq_validate, x509_certreq_decode, x509_free_aca, - x509_cert_obtain, x509_cert_get_key, x509_cert_get_subject} -}; - -struct cert_handler * -cert_get (u_int16_t id) -{ - int i; - - for (i = 0; i < sizeof cert_handler / sizeof cert_handler[0]; i++) - if (id == cert_handler[i].id) - return &cert_handler[i]; - return NULL; -} - - -/* Decode a CERTREQ and return a parsed structure */ - -struct certreq_aca * -certreq_decode (u_int16_t type, u_int8_t *data, u_int32_t datalen) -{ - struct cert_handler *handler; - struct certreq_aca aca, *ret; - - if ((handler = cert_get (type)) == NULL) - return NULL; - - aca.id = type; - aca.handler = handler; - - if (datalen > 0) - { - aca.data = handler->certreq_decode (data, datalen); - if (aca.data == NULL) - return NULL; - } - else - aca.data = NULL; - - if ((ret = malloc (sizeof (aca))) == NULL) - { - handler->free_aca (aca.data); - return NULL; - } - - memcpy (ret, &aca, sizeof (aca)); - - return ret; -} diff --git a/sbin/isakmpd/x509.c b/sbin/isakmpd/x509.c deleted file mode 100644 index 16b264ae126..00000000000 --- a/sbin/isakmpd/x509.c +++ /dev/null @@ -1,844 +0,0 @@ -/* $OpenBSD: x509.c,v 1.2 1998/11/15 00:44:05 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 <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <gmp.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "conf.h" -#include "exchange.h" -#include "hash.h" -#include "ike_auth.h" -#include "sa.h" -#include "ipsec.h" -#include "log.h" -#include "asn.h" -#include "asn_useful.h" -#include "pkcs.h" -#include "x509.h" - -/* X509 Certificate Handling functions */ - -/* Validate the BER Encoding of a RDNSequence in the CERT_REQ payload */ - -int -x509_certreq_validate (u_int8_t *asn, u_int32_t len) -{ - struct norm_type name = SEQOF ("issuer", RDNSequence); - int res = 1; - - if (asn_template_clone (&name, 1) == NULL || - (asn = asn_decode_sequence (asn, len, &name)) == NULL) - { - log_print ("x509_certreq_validate: can not decode 'acceptable CA' info"); - res = 0; - } - asn_free (&name); - - return res; -} - -/* Decode the BER Encoding of a RDNSequence in the CERT_REQ payload */ - -void * -x509_certreq_decode (u_int8_t *asn, u_int32_t len) -{ - struct norm_type aca = SEQOF ("aca", RDNSequence); - struct norm_type *tmp; - struct x509_aca naca, *ret; - - if (asn_template_clone (&aca, 1) == NULL || - (asn = asn_decode_sequence (asn, len, &aca)) == NULL) - { - log_print ("x509_certreq_validate: can not decode 'acceptable CA' info"); - goto fail; - } - memset (&naca, 0, sizeof (naca)); - - tmp = asn_decompose ("aca.RelativeDistinguishedName.AttributeValueAssertion", &aca); - if (tmp == NULL) - goto fail; - x509_get_attribval (tmp, &naca.name1); - - tmp = asn_decompose ("aca.RelativeDistinguishedName[1].AttributeValueAssertion", &aca); - if (tmp != NULL) - x509_get_attribval (tmp, &naca.name2); - - asn_free (&aca); - - if ((ret = malloc (sizeof (struct x509_aca))) != NULL) - memcpy (ret, &naca, sizeof (struct x509_aca)); - else - x509_free_aca (&aca); - - return ret; - - fail: - asn_free (&aca); - return NULL; -} - -void -x509_free_aca (void *blob) -{ - struct x509_aca *aca = blob; - - if (aca->name1.type != NULL) - free (aca->name1.type); - if (aca->name1.val != NULL) - free (aca->name1.val); - - if (aca->name2.type != NULL) - free (aca->name2.type); - if (aca->name2.val != NULL) - free (aca->name2.val); -} - -/* - * Obtain a Certificate from an acceptable Certification Authority. - * XXX - this is where all the magic should happen, but yet here - * you will find nothing :-\ - */ - -int -x509_cert_obtain (struct exchange *exchange, void *data, u_int8_t **cert, - u_int32_t *certlen) -{ - struct x509_aca *aca = data; - struct ipsec_exch *ie = exchange->data; - char *certfile; - int fd, res = 0; - struct stat st; - - if (aca != NULL) - log_debug (LOG_CRYPTO, 60, "x509_cert_obtain: (%s) %s, (%s) %s", - asn_parse_objectid (asn_ids, aca->name1.type), aca->name1.val, - asn_parse_objectid (asn_ids, aca->name2.type), aca->name2.val); - - /* XXX - this needs to be changed - but how else shoud I know */ - switch (ie->ike_auth->id) - { - case IKE_AUTH_RSA_SIG: - if ((certfile = conf_get_str ("rsa_sig", "cert")) == NULL) - return 0; - break; - default: - return 0; - } - - if (stat (certfile, &st) == -1) - { - log_error ("x509_cert_obtain: failed to state %s", certfile); - return 0; - } - - *certlen = st.st_size; - - if ((fd = open (certfile, O_RDONLY)) == -1) - { - log_error ("x509_cert_obtain: failed to open %s", certfile); - return 0; - } - - if ((*cert = malloc (st.st_size)) == NULL) - { - log_print ("x509_cert_obtain: out of memory"); - res = 0; - goto done; - } - - if (read (fd, *cert, st.st_size) != st.st_size) - { - log_print ("x509_cert_obtain: cert file ended early"); - free (*cert); - res = 0; - goto done; - } - - { - /* - * XXX - assumes IPv4 here, assumes a certificate with an extension - * type of subjectAltName at the end - this can go once the saved - * certificate is only used with one host with a fixed IP address - */ - u_int8_t *id_cert, *asn, *id; - size_t id_len; - u_int32_t id_cert_len; - - /* XXX - assumes IPv4 */ - id = exchange->initiator ? exchange->id_i : exchange->id_r; - id_len = exchange->initiator ? exchange->id_i_len : exchange->id_r_len; - - /* XXX - we need our ID to set that in the cert */ - if (id != NULL) - { - /* XXX - get to address ? */ - id += 4; id_len -= 4; - - /* Get offset into data structure where the IP is saved */ - asn = *cert; - id_cert_len = asn_get_data_len (NULL, &asn, &id_cert); - asn = id_cert; - id_cert_len = asn_get_data_len (NULL, &asn, &id_cert); - id_cert += id_cert_len - 4; - memcpy (id_cert, id, 4); - } - } - - res = 1; - - done: - close (fd); - - return res; -} - -/* Retrieve the public key from a X509 Certificate */ -int -x509_cert_get_key (u_int8_t *asn, u_int32_t asnlen, void *blob) -{ - struct rsa_public_key *key = blob; - struct x509_certificate cert; - - if (!x509_decode_certificate (asn, asnlen, &cert)) - return 0; - - /* XXX - perhaps put into pkcs ? */ - mpz_init_set (key->n, cert.key.n); - mpz_init_set (key->e, cert.key.e); - - x509_free_certificate (&cert); - - return 1; -} - -/* - * Retrieve the public key from a X509 Certificate - * XXX - look at XXX below. - */ - -int -x509_cert_get_subject (u_int8_t *asn, u_int32_t asnlen, - u_int8_t **subject, u_int32_t *subjectlen) -{ - struct x509_certificate cert; - - if (!x509_decode_certificate (asn, asnlen, &cert)) - return 0; - - if (cert.extension.type == NULL || cert.extension.val == NULL) - goto fail; - - log_debug (LOG_CRYPTO, 60, "x509_cert_get_subject: Extension Type %s = %s", - cert.extension.type, - asn_parse_objectid (asn_ids, cert.extension.type)); - - if (strcmp (ASN_ID_SUBJECT_ALT_NAME, cert.extension.type)) - { - log_print ("x509_cert_get_subject: extension type != subjectAltName"); - goto fail; - } - - /* - * XXX Evil**3, due to lack of time the IP encoding of subjectAltName - * is supposed to be: 0x30 0x06 0x087 0x04 aa bb cc dd, where the IPV4 - * IP number is aa.bb.cc.dd. - */ - - if (asn_get_len (cert.extension.val) != 8 || cert.extension.val[3] != 4) - { - log_print ("x509_cert_get_subject: subjectAltName uses " - "unhandled encoding"); - goto fail; - } - - /* XXX - 4 bytes for IPV4 address */ - *subject = malloc (4); - if (*subject == NULL) - { - log_print ("x509_cert_get_subject: out of memory"); - goto fail; - } - *subjectlen = 4; - memcpy (*subject, cert.extension.val + 4, *subjectlen); - - x509_free_certificate (&cert); - - return 1; - - fail: - x509_free_certificate (&cert); - return 0; -} - -/* Initalizes the struct x509_attribval from a AtributeValueAssertion */ - -void -x509_get_attribval (struct norm_type *obj, struct x509_attribval *a) -{ - struct norm_type *tmp; - - tmp = asn_decompose ("AttributeValueAssertion.AttributeType", obj); - if (tmp != NULL && tmp->data != NULL) - a->type = strdup ((char *)tmp->data); - - tmp = asn_decompose ("AttributeValueAssertion.AttributeValue", obj); - if (tmp != NULL && tmp->data != NULL) - a->val = strdup ((char *)tmp->data); -} - -/* Set's norm_type with values from x509_attribval */ - -void -x509_set_attribval (struct norm_type *obj, struct x509_attribval *a) -{ - struct norm_type *tmp; - - tmp = asn_decompose ("AttributeValueAssertion.AttributeType", obj); - tmp->data = strdup (a->type); - tmp->len = strlen (tmp->data); - tmp = asn_decompose ("AttributeValueAssertion.AttributeValue", obj); - tmp->type = TAG_PRINTSTRING; - tmp->data = strdup (a->val); - tmp->len = strlen (tmp->data); -} - -void -x509_free_attribval (struct x509_attribval *a) -{ - if (a->type != NULL) - free (a->type); - if (a->val != NULL) - free (a->val); -} - -void -x509_free_certificate (struct x509_certificate *cert) -{ - pkcs_free_public_key (&cert->key); - if (cert->signaturetype != NULL) - free (cert->signaturetype); - if (cert->start != NULL) - free (cert->start); - if (cert->end != NULL) - free (cert->end); - - x509_free_attribval (&cert->issuer1); - x509_free_attribval (&cert->issuer2); - x509_free_attribval (&cert->subject1); - x509_free_attribval (&cert->subject2); - x509_free_attribval (&cert->extension); -} - -int -x509_decode_certificate (u_int8_t *asn, u_int32_t asnlen, - struct x509_certificate *rcert) -{ - struct norm_type cert = SEQ ("cert", Certificate); - struct norm_type *tmp; - u_int8_t *data; - u_int32_t datalen; - - /* Get access to the inner Certificate */ - if (!x509_validate_signed (asn, asnlen, NULL, &data, &datalen)) - return 0; - - memset (rcert, 0, sizeof (*rcert)); - - if (asn_template_clone (&cert, 1) == NULL || - asn_decode_sequence (data, datalen, &cert) == NULL) - goto fail; - - tmp = asn_decompose ("cert.subjectPublicKeyInfo.subjectPublicKey", &cert); - if (!pkcs_public_key_from_asn (&rcert->key, tmp->data + 1, tmp->len - 1)) - goto fail; - - tmp = asn_decompose ("cert.version", &cert); - rcert->version = mpz_get_ui (tmp->data); - tmp = asn_decompose ("cert.serialNumber", &cert); - rcert->serialnumber = mpz_get_ui (tmp->data); - tmp = asn_decompose ("cert.signature.algorithm", &cert); - rcert->signaturetype = strdup ((char *)tmp->data); - - tmp = asn_decompose ("cert.issuer.RelativeDistinguishedName." - "AttributeValueAssertion", &cert); - x509_get_attribval (tmp, &rcert->issuer1); - tmp = asn_decompose ("cert.issuer.RelativeDistinguishedName[1]." - "AttributeValueAssertion", &cert); - if (tmp != NULL) - x509_get_attribval (tmp, &rcert->issuer2); - else - rcert->issuer2.type = NULL; - - tmp = asn_decompose ("cert.subject.RelativeDistinguishedName." - "AttributeValueAssertion", &cert); - x509_get_attribval (tmp, &rcert->subject1); - tmp = asn_decompose ("cert.subject.RelativeDistinguishedName[1]." - "AttributeValueAssertion", &cert); - if (tmp != NULL) - x509_get_attribval (tmp, &rcert->subject2); - else - rcert->subject2.type = NULL; - - tmp = asn_decompose ("cert.validity.notBefore", &cert); - rcert->start = strdup ((char *)tmp->data); - tmp = asn_decompose ("cert.validity.notAfter", &cert); - rcert->end = strdup ((char *)tmp->data); - - /* For x509v3 there might be an extension, try to decode it */ - tmp = asn_decompose ("cert.extension", &cert); - if (tmp && tmp->data && rcert->version == 2) - x509_decode_cert_extension (tmp->data, tmp->len, rcert); - - asn_free (&cert); - return 1; - - fail: - x509_free_certificate (rcert); - asn_free (&cert); - return 0; -} - -int -x509_encode_certificate (struct x509_certificate *rcert, - u_int8_t **asn, u_int32_t *asnlen) -{ - struct norm_type cert = SEQ ("cert", Certificate); - struct norm_type *tmp; - u_int8_t *data, *new_buf; - mpz_t num; - - if (asn_template_clone (&cert, 1) == NULL) - goto fail; - - if (rcert->extension.type != NULL && rcert->extension.val != NULL) - { - u_int8_t *asn; - u_int32_t asnlen; - - tmp = asn_decompose ("cert.extension", &cert); - if (x509_encode_cert_extension (rcert, &asn, &asnlen)) - { - tmp->data = asn; - tmp->len = asnlen; - } - } - - tmp = asn_decompose ("cert.subjectPublicKeyInfo.algorithm.parameters", - &cert); - tmp->type = TAG_NULL; - tmp = asn_decompose ("cert.subjectPublicKeyInfo.algorithm.algorithm", - &cert); - tmp->data = strdup (ASN_ID_RSAENCRYPTION); - tmp->len = strlen (tmp->data); - - tmp = asn_decompose ("cert.subjectPublicKeyInfo.subjectPublicKey", &cert); - data = pkcs_public_key_to_asn (&rcert->key); - if (data == NULL) - goto fail; - - /* This is a BIT STRING add 0 octet for padding */ - tmp->len = asn_get_len (data); - new_buf = realloc (data, tmp->len + 1); - if (new_buf == NULL) - { - free (data); - goto fail; - } - data = new_buf; - memmove (data + 1, data, tmp->len); - data[0] = 0; - tmp->data = data; - tmp->len++; - - mpz_init (num); - tmp = asn_decompose ("cert.version", &cert); - mpz_set_ui (num, rcert->version); - if (!pkcs_mpz_to_norm_type (tmp, num)) - { - mpz_clear (num); - goto fail; - } - - tmp = asn_decompose ("cert.serialNumber", &cert); - mpz_set_ui (num, rcert->serialnumber); - if (!pkcs_mpz_to_norm_type (tmp, num)) - { - mpz_clear (num); - goto fail; - } - mpz_clear (num); - - tmp = asn_decompose ("cert.signature.parameters", &cert); - tmp->type = TAG_NULL; - tmp = asn_decompose ("cert.signature.algorithm", &cert); - tmp->data = strdup (rcert->signaturetype); - tmp->len = strlen ((char *)tmp->data); - - tmp = asn_decompose ("cert.issuer.RelativeDistinguishedName." - "AttributeValueAssertion", &cert); - x509_set_attribval (tmp, &rcert->issuer1); - tmp = asn_decompose ("cert.issuer.RelativeDistinguishedName[1]." - "AttributeValueAssertion", &cert); - x509_set_attribval (tmp, &rcert->issuer2); - - tmp = asn_decompose ("cert.subject.RelativeDistinguishedName." - "AttributeValueAssertion", &cert); - x509_set_attribval (tmp, &rcert->subject1); - tmp = asn_decompose ("cert.subject.RelativeDistinguishedName[1]." - "AttributeValueAssertion", &cert); - x509_set_attribval (tmp, &rcert->subject2); - - tmp = asn_decompose ("cert.validity.notBefore", &cert); - tmp->data = strdup (rcert->start); - tmp->len = strlen ((char *)tmp->data); - - tmp = asn_decompose ("cert.validity.notAfter", &cert); - tmp->data = strdup (rcert->end); - tmp->len = strlen ((char *)tmp->data); - - *asn = asn_encode_sequence (&cert, NULL); - if (*asn == NULL) - goto fail; - - *asnlen = asn_get_len (*asn); - - asn_free (&cert); - return 1; - - fail: - asn_free (&cert); - return 0; -} - -/* - * Decode an Extension to a X509 certificate. - * XXX - We ignore the critical boolean - */ - -int -x509_decode_cert_extension (u_int8_t *asn, u_int32_t asnlen, - struct x509_certificate *cert) -{ - struct norm_type *tmp; - struct norm_type ex = SEQOF ("ex", Extensions); - - /* Implicit tagging for extension */ - ex.class = ADD_EXP (3, UNIVERSAL); - - if (asn_template_clone (&ex, 1) == NULL || - asn_decode_sequence (asn, asnlen, &ex) == NULL) - { - asn_free (&ex); - return 0; - } - - tmp = asn_decompose ("ex.extension.extnValue", &ex); - if (!tmp || tmp->data == NULL || asn_get_len (tmp->data) != tmp->len) - goto fail; - cert->extension.val = malloc (tmp->len); - if (cert->extension.val == 0) - goto fail; - memcpy (cert->extension.val, tmp->data, tmp->len); - - tmp = asn_decompose ("ex.extension.extnId", &ex); - if (!tmp || tmp->data == NULL) - goto fail; - cert->extension.type = strdup (tmp->data); - if (cert->extension.type == NULL) - { - free (cert->extension.val); - cert->extension.val = NULL; - goto fail; - } - - asn_free (&ex); - return 1; - - fail: - asn_free (&ex); - return 0; -} - -/* - * Encode a Cert Extension - XXX - only one extension per certificate - * XXX - We tag everything as critical - */ - -int -x509_encode_cert_extension (struct x509_certificate *cert, - u_int8_t **asn, u_int32_t *asnlen) -{ - struct norm_type ex = SEQ ("ex", Extensions); - struct norm_type *tmp; - ex.class = ADD_EXP (3, UNIVERSAL); - - if (asn_template_clone (&ex ,1) == NULL) - goto fail; - - tmp = asn_decompose ("ex.extension.extnId", &ex); - tmp->data = strdup (cert->extension.type); - tmp->len = strlen (tmp->data); - - /* XXX - we mark every extension as critical */ - tmp = asn_decompose ("ex.extension.critical", &ex); - if ((tmp->data = malloc (1)) == NULL) - goto fail; - *(u_int8_t *)tmp->data = 0xFF; - tmp->len = 1; - - tmp = asn_decompose ("ex.extension.extnValue", &ex); - if ((tmp->data = malloc (asn_get_len (cert->extension.val))) == NULL) - goto fail; - tmp->len = asn_get_len (cert->extension.val); - memcpy (tmp->data, cert->extension.val, tmp->len); - - *asn = asn_encode_sequence (&ex, NULL); - if (*asn == NULL) - goto fail; - - *asnlen = asn_get_len (*asn); - - asn_free (&ex); - return 1; - fail: - asn_free (&ex); - return 0; -} - -/* - * Checks the signature on an ASN.1 Signed Type. If the passed Key is - * NULL we just unwrap the inner object and return it. - */ - -int -x509_validate_signed (u_int8_t *asn, u_int32_t asnlen, - struct rsa_public_key *key, u_int8_t **data, - u_int32_t *datalen) -{ - struct norm_type sig = SEQ("signed", Signed); - struct norm_type digest = SEQ("digest", DigestInfo); - struct norm_type *tmp; - struct hash *hash = NULL; - int res; - u_int8_t *dec; - u_int16_t declen; - - if (asn_template_clone (&sig, 1) == NULL) - /* Failed, probably memory allocation, free what we got anyway */ - goto fail; - - if (asn_decode_sequence (asn, asnlen, &sig) == NULL) - { - log_print ("x509_validate_signed: input data could not be decoded"); - goto fail; - } - - tmp = asn_decompose ("signed.algorithm.algorithm", &sig); - - if (!strcmp ((char *)tmp->data, ASN_ID_MD5WITHRSAENC)) - { - hash = hash_get (HASH_MD5); - } - else - { - char *id = asn_parse_objectid (asn_ids, tmp->data); - log_print ("x509_validate_signed: can not handle SigType %s", - id == NULL ? tmp->data : id); - goto fail; - } - - if (hash == NULL) - goto fail; - - tmp = asn_decompose ("signed.data", &sig); - /* Hash the data */ - hash->Init (hash->ctx); - hash->Update (hash->ctx, tmp->data, tmp->len); - hash->Final (hash->digest, hash->ctx); - - *data = tmp->data; - *datalen = tmp->len; - - /* Used to unwrap the SIGNED object around the Certificate */ - if (key == NULL) - { - asn_free (&sig); - return 1; - } - - tmp = asn_decompose ("signed.encrypted", &sig); - /* - * tmp->data is a BIT STRING, the first octet in the BIT STRING gives - * the padding bits at the end. Per definition there are no padding - * bits at the end in this case, so just skip it. - */ - if (!pkcs_rsa_decrypt (PKCS_PRIVATE, key->n, key->e, tmp->data + 1, - &dec, &declen)) - goto fail; - - if (asn_template_clone (&digest, 1) == NULL || - asn_decode_sequence (dec, declen, &digest) == NULL) - { - asn_free (&digest); - goto fail; - } - tmp = asn_decompose ("digest.digestAlgorithm.algorithm", &digest); - if (strcmp (ASN_ID_MD5, (char *)tmp->data)) - { - log_print ("x509_validate_signed: DigestAlgorithm is not MD5"); - res = 0; - } - else - { - tmp = asn_decompose ("digest.digest", &digest); - if (tmp->len != hash->hashsize || - memcmp (tmp->data, hash->digest, tmp->len)) - { - log_print ("x509_validate_signed: Digest does not match Data"); - res = 0; - } - else - res = 1; - } - - asn_free (&digest); - asn_free (&sig); - return res; - - fail: - asn_free (&sig); - return 0; -} - -/* - * Create an ASN Signed Structure from the data passed in data - * and return the result in asn. - * At the moment the used hash is MD5, this is the only common - * hash between us and X509. - */ - -int -x509_create_signed (u_int8_t *data, u_int32_t datalen, - struct rsa_private_key *key, u_int8_t **asn, - u_int32_t *asnlen) -{ - struct norm_type digest = SEQ ("digest", DigestInfo); - struct norm_type sig = SEQ ("signed", Signed); - struct norm_type *tmp; - struct hash *hash; - u_int8_t *diginfo, *enc; - u_int32_t enclen; - int res = 0; - - /* Hash the Data */ - hash = hash_get (HASH_MD5); - hash->Init (hash->ctx); - hash->Update (hash->ctx, data, datalen); - hash->Final (hash->digest, hash->ctx); - - if (asn_template_clone (&digest, 1) == NULL) - goto fail; - - tmp = asn_decompose ("digest.digest", &digest); - tmp->len = hash->hashsize; - tmp->data = malloc (hash->hashsize); - if (tmp->data == NULL) - goto fail; - memcpy (tmp->data, hash->digest, hash->hashsize); - - tmp = asn_decompose ("digest.digestAlgorithm.parameters", &digest); - tmp->type = TAG_NULL; - tmp = asn_decompose ("digest.digestAlgorithm.algorithm", &digest); - tmp->data = strdup (ASN_ID_MD5); - tmp->len = strlen (tmp->data); - - /* ASN encode Digest Information */ - if ((diginfo = asn_encode_sequence (&digest, NULL)) == NULL) - goto fail; - - /* Encrypt the Digest Info with Private Key */ - res = pkcs_rsa_encrypt (PKCS_PRIVATE, key->n, key->d, diginfo, - asn_get_len (diginfo), &enc, &enclen); - free (diginfo); - if (!res) - goto fail; - res = 0; - - if (asn_template_clone (&sig, 1) == NULL) - goto fail2; - - tmp = asn_decompose ("signed.algorithm.parameters", &sig); - tmp->type = TAG_NULL; - tmp = asn_decompose ("signed.algorithm.algorithm", &sig); - tmp->data = strdup (ASN_ID_MD5WITHRSAENC); - tmp->len = strlen (tmp->data); - - /* The type is BITSTING, i.e. first octet need to be zero */ - tmp = asn_decompose ("signed.encrypted", &sig); - tmp->data = malloc (enclen + 1); - if (tmp->data == NULL) - { - free (enc); - goto fail2; - } - tmp->len = enclen + 1; - memcpy (tmp->data + 1, enc, enclen); - *(char *)tmp->data = 0; - free (enc); - - tmp = asn_decompose ("signed.data", &sig); - tmp->data = data; - tmp->len = datalen; - - *asn = asn_encode_sequence (&sig, NULL); - if (*asn == NULL) - goto fail2; - *asnlen = asn_get_len (*asn); - - /* This is the data we have been given, we can not free it in asn_free */ - tmp->data = NULL; - res = 1; /* Successfull */ - fail2: - asn_free (&sig); - fail: - asn_free (&digest); - return res; -} |