/** * @file der_encoder.c * * @brief Implementation of der_encoder_t. */ /* * Copyright (C) 2005 Jan Hutter, Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See . * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. */ #include #include "der_encoder.h" #include #include typedef struct private_der_encoder_t private_der_encoder_t; /** * Private data of a der_encoder_t object. */ struct private_der_encoder_t { /** * Public interface for this signer. */ der_encoder_t public; asn1_rule_t *rule; asn1_rule_t *first_rule; void *output; logger_t *logger; }; static status_t read_hdr(private_der_encoder_t *this, chunk_t *data); static status_t read_sequence(private_der_encoder_t *this, chunk_t data) { while (this->rule->type != ASN1_END) { read_hdr(this, &data); } return SUCCESS; } static status_t read_int(private_der_encoder_t *this, chunk_t data) { this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_INTEGER", data); u_int *integ = (u_int*)((u_int8_t*)this->output + this->rule->data_offset); *integ = 0; while (data.len-- > 0) { *integ = 256 * (*integ) + *data.ptr++; } return SUCCESS; } static status_t read_mpz(private_der_encoder_t *this, chunk_t data) { this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_INTEGER as mpz", data); mpz_t *mpz = (mpz_t*)((u_int8_t*)this->output + this->rule->data_offset); mpz_import(*mpz, data.len, 1, 1, 1, 0, data.ptr); return SUCCESS; } static u_int32_t read_length(chunk_t *data) { u_int8_t n; size_t len; /* read first octet of length field */ n = *data->ptr++; if ((n & 0x80) == 0) { /* single length octet */ return n; } /* composite length, determine number of length octets */ n &= 0x7f; if (n > data->len) { /* length longer than available bytes */ return -1; } if (n > sizeof(len)) { /* larger than size_t can hold */ return -1; } len = 0; while (n-- > 0) { len = 256 * len + *data->ptr++; } return len; } static status_t read_hdr(private_der_encoder_t *this, chunk_t *data) { chunk_t inner; /* advance to the next rule */ this->rule++; if (this->rule->type == ASN1_END) { return SUCCESS; } this->logger->log(this->logger, CONTROL|LEVEL2, "reading header of rule %s", mapping_find(asn1_type_m, this->rule->type)); this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "reading from:", *data); /* read type, advance in data */ if (*(data->ptr) != this->rule->type) { this->logger->log(this->logger, CONTROL|LEVEL2, "Bad byte found (%x)", *data->ptr); return PARSE_ERROR; } data->ptr++; data->len--; /* read length, advance in data */ inner.len = read_length(data); if (inner.len == -1) { this->logger->log(this->logger, CONTROL|LEVEL2, "Error reading length"); return PARSE_ERROR; } this->logger->log(this->logger, CONTROL|LEVEL2, "Length is %d", inner.len); inner.ptr = data->ptr; /* advance in data */ data->ptr += inner.len; data->len -= inner.len; /* process inner */ switch (this->rule->type) { case ASN1_INTEGER: if (this->rule->flags & ASN1_MPZ) { read_mpz(this, inner); } else { read_int(this, inner); } break; case ASN1_SEQUENCE: read_sequence(this, inner); break; default: break; } return SUCCESS; } static status_t decode(private_der_encoder_t *this, chunk_t input, void *output) { this->rule = this->first_rule - 1; this->output = output; return read_hdr(this, &input); } /** * Implementation of der_encoder.destroy. */ static void destroy(private_der_encoder_t *this) { allocator_free(this); } /* * Described in header. */ der_encoder_t *der_encoder_create(asn1_rule_t *rules) { private_der_encoder_t *this = allocator_alloc_thing(private_der_encoder_t); /* public functions */ this->public.decode = (status_t (*) (der_encoder_t*,chunk_t,void*))decode; this->public.destroy = (void (*) (der_encoder_t*))destroy; this->first_rule = rules; this->logger = charon->logger_manager->get_logger(charon->logger_manager, DER_DECODER); return &(this->public); }