/*
 * asn1rsa.c
 *
 *  Created on: May 16, 2013
 *      Author: ignat
 */

#include "asn1rsa.h"

rsa_parse_error_t rsa_private_key_parse(const u8 *buf, size_t len, struct rsa_private_key * key)
{
    struct asn1_hdr hdr;
    const u8* key_end;
    const u8* pos;

    if (!buf || !len || !key)
        return RSA_PARSE_ERROR;

    if (asn1_get_next(buf, len, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE)
        return RSA_PARSE_ERROR;

    key_end = hdr.payload + hdr.length;

    // version
    if (asn1_get_next(hdr.payload, hdr.length, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    pos = hdr.payload + hdr.length;

    // modulus
    if (asn1_get_next(pos, key_end - pos, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->modulus = hdr.payload + 1;
        key->modulus_len = hdr.length - 1;
    }
    else
    {
        key->modulus = hdr.payload;
        key->modulus_len = hdr.length;
    }

    pos = hdr.payload + hdr.length;

    // public exponent
    if (asn1_get_next(pos, key_end - pos, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->public_exponent = hdr.payload + 1;
        key->public_exponent_len = hdr.length - 1;
    }
    else
    {
        key->public_exponent = hdr.payload;
        key->public_exponent_len = hdr.length;
    }

    pos = hdr.payload + hdr.length;

    // private exponent
    if (asn1_get_next(pos, key_end - pos, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->private_exponent = hdr.payload + 1;
        key->private_exponent_len = hdr.length - 1;
    }
    else
    {
        key->private_exponent = hdr.payload;
        key->private_exponent_len = hdr.length;
    }

    pos = hdr.payload + hdr.length;

    if (asn1_get_next(pos, key_end - pos, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->prime1 = hdr.payload + 1;
        key->prime1_len = hdr.length - 1;
    }
    else
    {
        key->prime1 = hdr.payload;
        key->prime1_len = hdr.length;
    }
    pos = hdr.payload + hdr.length;

    if (asn1_get_next(pos, key_end - pos, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->prime2 = hdr.payload + 1;
        key->prime2_len = hdr.length - 1;
    }
    else
    {
        key->prime2 = hdr.payload;
        key->prime2_len = hdr.length;
    }
    pos = hdr.payload + hdr.length;

    if (asn1_get_next(pos, key_end - pos, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->exponent1 = hdr.payload + 1;
        key->exponent1_len = hdr.length - 1;
    }
    else
    {
        key->exponent1 = hdr.payload;
        key->exponent1_len = hdr.length;
    }
    pos = hdr.payload + hdr.length;
    if (asn1_get_next(pos, key_end - pos, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->exponent2 = hdr.payload + 1;
        key->exponent2_len = hdr.length - 1;
    }
    else
    {
        key->exponent2 = hdr.payload;
        key->exponent2_len = hdr.length;
    }
    pos = hdr.payload + hdr.length;

    if (asn1_get_next(pos, key_end - pos, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->coefficient = hdr.payload + 1;
        key->coefficient_len = hdr.length - 1;
    }
    else
    {
        key->coefficient = hdr.payload;
        key->coefficient_len = hdr.length;
    }

    return RSA_PARSE_OK;
}

rsa_parse_error_t rsa_public_key_parse(const u8 *buf, size_t len, struct rsa_public_key * key)
{
    struct asn1_hdr hdr;
    const u8* key_end;

    if (!buf || !len || !key)
        return RSA_PARSE_ERROR;

    if (asn1_get_next(buf, len, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SEQUENCE)
        return RSA_PARSE_ERROR;

    key_end = hdr.payload + hdr.length;

    if (asn1_get_next(hdr.payload, hdr.length, &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    if (0x00 == hdr.payload[0])
    {
        key->modulus = hdr.payload + 1;
        key->modulus_len = hdr.length - 1;
    }
    else
    {
        key->modulus = hdr.payload;
        key->modulus_len = hdr.length;
    }

    if (asn1_get_next(hdr.payload + hdr.length, key_end - (hdr.payload + hdr.length), &hdr) || hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER)
        return RSA_PARSE_ERROR;

    key->exponent = hdr.payload;
    key->exponent_len = hdr.length;

    return RSA_PARSE_OK;
}
