/*
* X.509 certificate and private key decoding
*
* Copyright (C) 2006-2007 Christophe Devine
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License, version 2.1 as published by the Free Software Foundation.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
/*
* The ITU-T X.509 standard defines a certificat format for PKI.
*
* http://www.ietf.org/rfc/rfc2459.txt
* http://www.ietf.org/rfc/rfc3279.txt
*
* ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc
*
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
*/
#include "xyssl/config.h"
#if defined(XYSSL_X509_PARSE_C)
#include "xyssl/x509.h"
#include "xyssl/base64.h"
#include "xyssl/des.h"
#include "xyssl/md2.h"
#include "xyssl/md4.h"
#include "xyssl/md5.h"
#include "xyssl/sha1.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
/*
* ASN.1 DER decoding routines
*/
static int asn1_get_len( unsigned char **p,
unsigned char *end,
int *len )
{
if( ( end - *p ) < 1 )
return( XYSSL_ERR_ASN1_OUT_OF_DATA );
if( ( **p & 0x80 ) == 0 )
*len = *(*p)++;
else
{
switch( **p & 0x7F )
{
case 1:
if( ( end - *p ) < 2 )
return( XYSSL_ERR_ASN1_OUT_OF_DATA );
*len = (*p)[1];
(*p) += 2;
break;
case 2:
if( ( end - *p ) < 3 )
return( XYSSL_ERR_ASN1_OUT_OF_DATA );
*len = ( (*p)[1] << 8 ) | (*p)[2];
(*p) += 3;
break;
default:
return( XYSSL_ERR_ASN1_INVALID_LENGTH );
break;
}
}
if( *len > (int) ( end - *p ) )
return( XYSSL_ERR_ASN1_OUT_OF_DATA );
return( 0 );
}
static int asn1_get_tag( unsigned char **p,
unsigned char *end,
int *len, int tag )
{
if( ( end - *p ) < 1 )
return( XYSSL_ERR_ASN1_OUT_OF_DATA );
if( **p != tag )
return( XYSSL_ERR_ASN1_UNEXPECTED_TAG );
(*p)++;
return( asn1_get_len( p, end, len ) );
}
static int asn1_get_bool( unsigned char **p,
unsigned char *end,
int *val )
{
int ret, len;
if( ( ret = asn1_get_tag( p, end, &len, ASN1_BOOLEAN ) ) != 0 )
return( ret );
if( len != 1 )
return( XYSSL_ERR_ASN1_INVALID_LENGTH );
*val = ( **p != 0 ) ? 1 : 0;
(*p)++;
return( 0 );
}
static int asn1_get_int( unsigned char **p,
unsigned char *end,
int *val )
{
int ret, len;
if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 )
return( ret );
if( len > (int) sizeof( int ) || ( **p & 0x80 ) != 0 )
return( XYSSL_ERR_ASN1_INVALID_LENGTH );
*val = 0;
while( len-- > 0 )
{
*val = ( *val << 8 ) | **p;
(*p)++;
}
return( 0 );
}
static int asn1_get_mpi( unsigned char **p,
unsigned char *end,
mpi *X )
{
int ret, len;
if( ( ret = asn1_get_tag( p, end, &len, ASN1_INTEGER ) ) != 0 )
return( ret );
ret = mpi_read_binary( X, *p, len );
*p += len;
return( ret );
}
/*
* Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
static int x509_get_version( unsigned char **p,
unsigned char *end,
int *ver )
{
int ret, len;
if( ( ret = asn1_get_tag( p, end, &len,
ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ) != 0 )
{
if( ret == XYSSL_ERR_ASN1_UNEXPECTED_TAG )
return( *ver = 0 );
return( ret );
}
end = *p + len;
if( ( ret = asn1_get_int( p, end, ver ) ) != 0 )
return( XYSSL_ERR_X509_CERT_INVALID_VERSION | ret );
if( *p != end )
return( XYSSL_ERR_X509_CERT_INVALID_VERSION |
XYSSL_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
/*
* CertificateSerialNumber ::= INTEGER
*/
static int x509_get_serial( unsigned char **p,
unsigned char *end,
x509_buf *serial )
{
int ret;
if( ( end - *p ) < 1 )
return( XYSSL_ERR_X509_CERT_INVALID_SERIAL |
XYSSL_ERR_ASN1_OUT_OF_DATA );
if( **p != ( ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2 ) &&
**p != ASN1_INTEGER )
return( XYSSL_ERR_X509_CERT_INVALID_SERIAL |
XYSSL_ERR_ASN1_UNEXPECTED_TAG );
serial->tag = *(*p)++;
if( ( ret = asn1_get_len( p, end, &serial->len ) ) != 0 )
return( XYSSL_ERR_X509_CERT_INVALID_SERIAL | ret );
serial->p = *p;
*p += serial->len;
return( 0 );
}
/*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL }
*/
static int x509_get_alg( unsigned char **p,
unsigned char *end,
x509_buf *alg )
{
int ret, len;
if( ( ret = asn1_get_tag( p, end, &len,
ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
return( XYSSL_ERR_X509_CERT_INVALID_ALG | ret );
end = *p + len;
alg->tag = **p;
if( ( ret = asn1_get_tag( p, end, &alg->len, ASN1_OID ) ) != 0 )
return( XYSSL_ERR_X509_CERT_INVALID_ALG | ret );
alg->p = *p;
*p += alg->len;
if( *p == end )
return( 0 );
/*
* assume the algorithm parameters must be NULL
*/
if( ( ret = asn1_get_tag( p, end, &len, ASN1_NULL ) ) != 0 )
return( XYSSL_ERR_X509_CERT_INVALID_ALG | ret );
if( *p != end )
return( XYSSL_ERR_X509_CERT_INVALID_ALG |
XYSSL_ERR_ASN1_LENGTH_MISMATCH );
return( 0 );
}
/*
* RelativeDistinguishedName ::=
* SET OF AttributeTypeAndValue
*
* AttributeTypeAndValue ::= SEQUENCE {
* type AttributeType,
* value AttributeValue }
*
* AttributeType ::= OBJECT IDENTIFIER
*
* AttributeValue ::= ANY DEFINED BY AttributeType
*/
static int x509_get_name( unsigned char **p,
unsigned char *end,
x509_name *cur )
{
int ret, len;
unsigned char *end2;
x509_buf *oid;
x509_buf *val;
if( ( ret = asn1_get_tag( p, end, &len,
ASN1_CONSTRUCTED | ASN1_SET ) ) != 0 )
return( XYSSL_ERR_X509_CERT_INVALID_NAME | ret );
end2 = end;
end = *p + len;
if( ( ret = asn1_get_tag( p, end, &len,
ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
return( XYSSL_ERR_X509_CERT_INVALID_NAME | ret );
if( *p + len != end )
return( XYSSL_ERR_X509_CERT_INVALID_NAME |
XYSSL_ERR_ASN1_LENGTH_MISMATCH );
oid = &cur->oid;
oid->tag = **p;
if( ( ret = asn1_get_tag( p, end, &oid->len, ASN1_OID ) ) != 0 )
return( XYSSL_ERR_X509_CERT_INVALID_NAME | ret );
oid->p = *p;
*p += oid->len;
if( ( end - *p ) < 1 )
return( XYSSL_ERR_X509_CERT_INVALID_NAME |
XYSSL_ERR_ASN1_OUT_OF_DATA );
if( **p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING &&
**p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING &&
**p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING )
return( XYSSL_ERR_X509_CERT_INVALID_NAME |
评论16
最新资源