|
|
/*
* Generic ASN.1 parsing * * Copyright The Mbed TLS Contributors * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later * * This file is provided under the Apache License 2.0, or the * GNU General Public License v2.0 or later. * * ********** * Apache License 2.0: * * Licensed under the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0
* * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ********** * * ********** * GNU General Public License v2.0 or later: * * 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. * * 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. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * ********** */
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_ASN1_PARSE_C)
#include "mbedtls/asn1.h"
#include "mbedtls/platform_util.h"
#include <string.h>
#if defined(MBEDTLS_BIGNUM_C)
#include "mbedtls/bignum.h"
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdlib.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
/*
* ASN.1 DER decoding routines */ int mbedtls_asn1_get_len( unsigned char **p, const unsigned char *end, size_t *len ) { if( ( end - *p ) < 1 ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( ( **p & 0x80 ) == 0 ) *len = *(*p)++; else { switch( **p & 0x7F ) { case 1: if( ( end - *p ) < 2 ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = (*p)[1]; (*p) += 2; break;
case 2: if( ( end - *p ) < 3 ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 8 ) | (*p)[2]; (*p) += 3; break;
case 3: if( ( end - *p ) < 4 ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 16 ) | ( (size_t)(*p)[2] << 8 ) | (*p)[3]; (*p) += 4; break;
case 4: if( ( end - *p ) < 5 ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
*len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) | ( (size_t)(*p)[3] << 8 ) | (*p)[4]; (*p) += 5; break;
default: return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); } }
if( *len > (size_t) ( end - *p ) ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
return( 0 ); }
int mbedtls_asn1_get_tag( unsigned char **p, const unsigned char *end, size_t *len, int tag ) { if( ( end - *p ) < 1 ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
if( **p != tag ) return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
(*p)++;
return( mbedtls_asn1_get_len( p, end, len ) ); }
int mbedtls_asn1_get_bool( unsigned char **p, const unsigned char *end, int *val ) { int ret; size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 ) return( ret );
if( len != 1 ) return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
*val = ( **p != 0 ) ? 1 : 0; (*p)++;
return( 0 ); }
int mbedtls_asn1_get_int( unsigned char **p, const unsigned char *end, int *val ) { int ret; size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) return( ret );
if( len == 0 || len > sizeof( int ) || ( **p & 0x80 ) != 0 ) return( MBEDTLS_ERR_ASN1_INVALID_LENGTH );
*val = 0;
while( len-- > 0 ) { *val = ( *val << 8 ) | **p; (*p)++; }
return( 0 ); }
#if defined(MBEDTLS_BIGNUM_C)
int mbedtls_asn1_get_mpi( unsigned char **p, const unsigned char *end, mbedtls_mpi *X ) { int ret; size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) return( ret );
ret = mbedtls_mpi_read_binary( X, *p, len );
*p += len;
return( ret ); } #endif /* MBEDTLS_BIGNUM_C */
int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, mbedtls_asn1_bitstring *bs) { int ret;
/* Certificate type is a single byte bitstring */ if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) return( ret );
/* Check length, subtract one for actual bit string length */ if( bs->len < 1 ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); bs->len -= 1;
/* Get number of unused bits, ensure unused bits <= 7 */ bs->unused_bits = **p; if( bs->unused_bits > 7 ) return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); (*p)++;
/* Get actual bitstring */ bs->p = *p; *p += bs->len;
if( *p != end ) return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 ); }
/*
* Get a bit string without unused bits */ int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, size_t *len ) { int ret;
if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) return( ret );
if( (*len)-- < 2 || *(*p)++ != 0 ) return( MBEDTLS_ERR_ASN1_INVALID_DATA );
return( 0 ); }
/*
* Parses and splits an ASN.1 "SEQUENCE OF <tag>" */ int mbedtls_asn1_get_sequence_of( unsigned char **p, const unsigned char *end, mbedtls_asn1_sequence *cur, int tag) { int ret; size_t len; mbedtls_asn1_buf *buf;
/* Get main sequence tag */ if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( ret );
if( *p + len != end ) return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
while( *p < end ) { buf = &(cur->buf); buf->tag = **p;
if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 ) return( ret );
buf->p = *p; *p += buf->len;
/* Allocate and assign next pointer */ if( *p < end ) { cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) );
if( cur->next == NULL ) return( MBEDTLS_ERR_ASN1_ALLOC_FAILED );
cur = cur->next; } }
/* Set final sequence entry's next pointer to NULL */ cur->next = NULL;
if( *p != end ) return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 ); }
int mbedtls_asn1_get_alg( unsigned char **p, const unsigned char *end, mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ) { int ret; size_t len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) return( ret );
if( ( end - *p ) < 1 ) return( MBEDTLS_ERR_ASN1_OUT_OF_DATA );
alg->tag = **p; end = *p + len;
if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 ) return( ret );
alg->p = *p; *p += alg->len;
if( *p == end ) { mbedtls_platform_zeroize( params, sizeof(mbedtls_asn1_buf) ); return( 0 ); }
params->tag = **p; (*p)++;
if( ( ret = mbedtls_asn1_get_len( p, end, ¶ms->len ) ) != 0 ) return( ret );
params->p = *p; *p += params->len;
if( *p != end ) return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
return( 0 ); }
int mbedtls_asn1_get_alg_null( unsigned char **p, const unsigned char *end, mbedtls_asn1_buf *alg ) { int ret; mbedtls_asn1_buf params;
memset( ¶ms, 0, sizeof(mbedtls_asn1_buf) );
if( ( ret = mbedtls_asn1_get_alg( p, end, alg, ¶ms ) ) != 0 ) return( ret );
if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 ) return( MBEDTLS_ERR_ASN1_INVALID_DATA );
return( 0 ); }
void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur ) { if( cur == NULL ) return;
mbedtls_free( cur->oid.p ); mbedtls_free( cur->val.p );
mbedtls_platform_zeroize( cur, sizeof( mbedtls_asn1_named_data ) ); }
void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ) { mbedtls_asn1_named_data *cur;
while( ( cur = *head ) != NULL ) { *head = cur->next; mbedtls_asn1_free_named_data( cur ); mbedtls_free( cur ); } }
mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, const char *oid, size_t len ) { while( list != NULL ) { if( list->oid.len == len && memcmp( list->oid.p, oid, len ) == 0 ) { break; }
list = list->next; }
return( list ); }
#endif /* MBEDTLS_ASN1_PARSE_C */
|