2016-01-31 13:12:23 +03:00
/*
2003-08-13 05:53:07 +04:00
Unix SMB / CIFS implementation .
2008-01-08 23:27:40 +03:00
simple ASN1 routines
2003-08-13 05:53:07 +04:00
Copyright ( C ) Andrew Tridgell 2001
2016-01-31 13:12:23 +03:00
2003-08-13 05:53:07 +04:00
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( at your option ) any later version .
2016-01-31 13:12:23 +03:00
2003-08-13 05:53:07 +04:00
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 .
2016-01-31 13:12:23 +03:00
2003-08-13 05:53:07 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
2016-01-06 00:00:58 +03:00
# include "replace.h"
# include "system/locale.h"
# include "lib/util/asn1.h"
# include "lib/util/debug.h"
# include "lib/util/samba_util.h"
2003-08-13 05:53:07 +04:00
2015-12-27 13:18:47 +03:00
struct nesting {
off_t start ;
size_t taglen ; /* for parsing */
struct nesting * next ;
} ;
2016-01-03 23:26:50 +03:00
struct asn1_data {
uint8_t * data ;
size_t length ;
off_t ofs ;
struct nesting * nesting ;
bool has_error ;
} ;
2007-05-21 10:12:06 +04:00
/* allocate an asn1 structure */
struct asn1_data * asn1_init ( TALLOC_CTX * mem_ctx )
{
2007-05-21 17:33:46 +04:00
struct asn1_data * ret = talloc_zero ( mem_ctx , struct asn1_data ) ;
2007-05-21 16:47:18 +04:00
if ( ret = = NULL ) {
DEBUG ( 0 , ( " asn1_init failed! out of memory \n " ) ) ;
}
return ret ;
2007-05-21 10:12:06 +04:00
}
2003-08-13 05:53:07 +04:00
/* free an asn1 structure */
2004-11-02 09:42:15 +03:00
void asn1_free ( struct asn1_data * data )
2003-08-13 05:53:07 +04:00
{
2007-05-21 10:12:06 +04:00
talloc_free ( data ) ;
2003-08-13 05:53:07 +04:00
}
2016-01-02 19:58:21 +03:00
bool asn1_has_error ( const struct asn1_data * data )
{
return data - > has_error ;
}
2016-01-04 23:50:49 +03:00
void asn1_set_error ( struct asn1_data * data )
{
data - > has_error = true ;
}
2016-01-04 12:23:20 +03:00
bool asn1_has_nesting ( const struct asn1_data * data )
{
return data - > nesting ! = NULL ;
}
2016-01-04 12:25:41 +03:00
off_t asn1_current_ofs ( const struct asn1_data * data )
{
return data - > ofs ;
}
2003-08-13 05:53:07 +04:00
/* write to the ASN1 buffer, advancing the buffer pointer */
2007-10-07 02:28:14 +04:00
bool asn1_write ( struct asn1_data * data , const void * p , int len )
2003-08-13 05:53:07 +04:00
{
2007-10-07 02:28:14 +04:00
if ( data - > has_error ) return false ;
2015-12-22 15:50:54 +03:00
if ( ( len < 0 ) | | ( data - > ofs + ( size_t ) len < data - > ofs ) ) {
data - > has_error = true ;
return false ;
}
2003-08-13 05:53:07 +04:00
if ( data - > length < data - > ofs + len ) {
2004-05-25 21:50:17 +04:00
uint8_t * newp ;
2007-05-21 10:12:06 +04:00
newp = talloc_realloc ( data , data - > data , uint8_t , data - > ofs + len ) ;
2003-08-13 05:53:07 +04:00
if ( ! newp ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
data - > data = newp ;
data - > length = data - > ofs + len ;
}
memcpy ( data - > data + data - > ofs , p , len ) ;
data - > ofs + = len ;
2007-10-07 02:28:14 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2004-05-25 21:50:17 +04:00
/* useful fn for writing a uint8_t */
2007-10-07 02:28:14 +04:00
bool asn1_write_uint8 ( struct asn1_data * data , uint8_t v )
2003-08-13 05:53:07 +04:00
{
return asn1_write ( data , & v , 1 ) ;
}
/* push a tag onto the asn1 data buffer. Used for nested structures */
2007-10-07 02:28:14 +04:00
bool asn1_push_tag ( struct asn1_data * data , uint8_t tag )
2003-08-13 05:53:07 +04:00
{
struct nesting * nesting ;
2015-12-27 12:57:07 +03:00
if ( ! asn1_write_uint8 ( data , tag ) ) {
return false ;
}
2007-05-21 10:12:06 +04:00
nesting = talloc ( data , struct nesting ) ;
2003-08-13 05:53:07 +04:00
if ( ! nesting ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
nesting - > start = data - > ofs ;
nesting - > next = data - > nesting ;
data - > nesting = nesting ;
return asn1_write_uint8 ( data , 0xff ) ;
}
/* pop a tag */
2007-10-07 02:28:14 +04:00
bool asn1_pop_tag ( struct asn1_data * data )
2003-08-13 05:53:07 +04:00
{
struct nesting * nesting ;
size_t len ;
2015-12-27 12:57:07 +03:00
if ( data - > has_error ) {
return false ;
}
2003-08-13 05:53:07 +04:00
nesting = data - > nesting ;
if ( ! nesting ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
len = data - > ofs - ( nesting - > start + 1 ) ;
/* yes, this is ugly. We don't know in advance how many bytes the length
2016-01-31 13:12:23 +03:00
of a tag will take , so we assumed 1 byte . If we were wrong then we
2003-08-13 05:53:07 +04:00
need to correct our mistake */
2007-02-23 10:32:13 +03:00
if ( len > 0xFFFFFF ) {
data - > data [ nesting - > start ] = 0x84 ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
2007-02-23 10:32:13 +03:00
memmove ( data - > data + nesting - > start + 5 , data - > data + nesting - > start + 1 , len ) ;
data - > data [ nesting - > start + 1 ] = ( len > > 24 ) & 0xFF ;
data - > data [ nesting - > start + 2 ] = ( len > > 16 ) & 0xFF ;
data - > data [ nesting - > start + 3 ] = ( len > > 8 ) & 0xFF ;
data - > data [ nesting - > start + 4 ] = len & 0xff ;
} else if ( len > 0xFFFF ) {
2005-06-27 11:02:39 +04:00
data - > data [ nesting - > start ] = 0x83 ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
2005-06-27 11:02:39 +04:00
memmove ( data - > data + nesting - > start + 4 , data - > data + nesting - > start + 1 , len ) ;
data - > data [ nesting - > start + 1 ] = ( len > > 16 ) & 0xFF ;
data - > data [ nesting - > start + 2 ] = ( len > > 8 ) & 0xFF ;
data - > data [ nesting - > start + 3 ] = len & 0xff ;
} else if ( len > 255 ) {
2003-08-13 05:53:07 +04:00
data - > data [ nesting - > start ] = 0x82 ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
2003-08-13 05:53:07 +04:00
memmove ( data - > data + nesting - > start + 3 , data - > data + nesting - > start + 1 , len ) ;
data - > data [ nesting - > start + 1 ] = len > > 8 ;
data - > data [ nesting - > start + 2 ] = len & 0xff ;
} else if ( len > 127 ) {
data - > data [ nesting - > start ] = 0x81 ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_write_uint8 ( data , 0 ) ) return false ;
2003-08-13 05:53:07 +04:00
memmove ( data - > data + nesting - > start + 2 , data - > data + nesting - > start + 1 , len ) ;
data - > data [ nesting - > start + 1 ] = len ;
} else {
data - > data [ nesting - > start ] = len ;
}
data - > nesting = nesting - > next ;
2004-08-25 06:05:02 +04:00
talloc_free ( nesting ) ;
2007-10-07 02:28:14 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2004-09-01 11:29:02 +04:00
/* "i" is the one's complement representation, as is the normal result of an
* implicit signed - > unsigned conversion */
2007-10-07 02:28:14 +04:00
static bool push_int_bigendian ( struct asn1_data * data , unsigned int i , bool negative )
2004-08-31 10:21:14 +04:00
{
uint8_t lowest = i & 0xFF ;
i = i > > 8 ;
if ( i ! = 0 )
2004-09-15 17:29:59 +04:00
if ( ! push_int_bigendian ( data , i , negative ) )
2007-10-07 02:28:14 +04:00
return false ;
2004-09-01 11:29:02 +04:00
if ( data - > nesting - > start + 1 = = data - > ofs ) {
/* We did not write anything yet, looking at the highest
* valued byte */
if ( negative ) {
/* Don't write leading 0xff's */
if ( lowest = = 0xFF )
2007-10-07 02:28:14 +04:00
return true ;
2004-09-01 11:29:02 +04:00
if ( ( lowest & 0x80 ) = = 0 ) {
/* The only exception for a leading 0xff is if
* the highest bit is 0 , which would indicate
* a positive value */
2004-09-15 17:29:59 +04:00
if ( ! asn1_write_uint8 ( data , 0xff ) )
2007-10-07 02:28:14 +04:00
return false ;
2004-09-01 11:29:02 +04:00
}
} else {
if ( lowest & 0x80 ) {
/* The highest bit of a positive integer is 1,
* this would indicate a negative number . Push
* a 0 to indicate a positive one */
2004-09-15 17:29:59 +04:00
if ( ! asn1_write_uint8 ( data , 0 ) )
2007-10-07 02:28:14 +04:00
return false ;
2004-09-01 11:29:02 +04:00
}
}
}
2004-08-31 10:21:14 +04:00
2004-09-15 17:29:59 +04:00
return asn1_write_uint8 ( data , lowest ) ;
2004-08-31 10:21:14 +04:00
}
2004-09-15 17:29:59 +04:00
/* write an Integer without the tag framing. Needed for example for the LDAP
* Abandon Operation */
2007-10-07 02:28:14 +04:00
bool asn1_write_implicit_Integer ( struct asn1_data * data , int i )
2003-08-13 05:53:07 +04:00
{
2015-12-27 12:57:07 +03:00
if ( data - > has_error ) {
return false ;
}
2004-09-01 11:29:02 +04:00
if ( i = = - 1 ) {
/* -1 is special as it consists of all-0xff bytes. In
push_int_bigendian this is the only case that is not
properly handled , as all 0xff bytes would be handled as
leading ones to be ignored . */
2004-09-15 17:29:59 +04:00
return asn1_write_uint8 ( data , 0xff ) ;
2004-09-01 11:29:02 +04:00
} else {
2004-09-15 17:29:59 +04:00
return push_int_bigendian ( data , i , i < 0 ) ;
2004-09-01 11:29:02 +04:00
}
2004-09-15 17:29:59 +04:00
}
/* write an integer */
2007-10-07 02:28:14 +04:00
bool asn1_write_Integer ( struct asn1_data * data , int i )
2004-09-15 17:29:59 +04:00
{
2007-10-07 02:28:14 +04:00
if ( ! asn1_push_tag ( data , ASN1_INTEGER ) ) return false ;
if ( ! asn1_write_implicit_Integer ( data , i ) ) return false ;
2003-08-13 05:53:07 +04:00
return asn1_pop_tag ( data ) ;
}
2009-08-13 10:12:01 +04:00
/* write a BIT STRING */
bool asn1_write_BitString ( struct asn1_data * data , const void * p , size_t length , uint8_t padding )
{
if ( ! asn1_push_tag ( data , ASN1_BIT_STRING ) ) return false ;
if ( ! asn1_write_uint8 ( data , padding ) ) return false ;
if ( ! asn1_write ( data , p , length ) ) return false ;
return asn1_pop_tag ( data ) ;
}
2009-10-05 05:46:20 +04:00
bool ber_write_OID_String ( TALLOC_CTX * mem_ctx , DATA_BLOB * blob , const char * OID )
2003-08-13 05:53:07 +04:00
{
2010-01-05 20:40:54 +03:00
unsigned int v , v2 ;
2003-08-13 05:53:07 +04:00
const char * p = ( const char * ) OID ;
char * newp ;
2006-12-20 18:51:02 +03:00
int i ;
2003-08-13 05:53:07 +04:00
2010-10-20 14:45:59 +04:00
if ( ! isdigit ( * p ) ) return false ;
2006-12-19 22:25:49 +03:00
v = strtoul ( p , & newp , 10 ) ;
2007-10-07 02:28:14 +04:00
if ( newp [ 0 ] ! = ' . ' ) return false ;
2006-12-19 22:25:49 +03:00
p = newp + 1 ;
2006-12-20 18:51:02 +03:00
2010-10-20 14:45:59 +04:00
if ( ! isdigit ( * p ) ) return false ;
2006-12-19 22:25:49 +03:00
v2 = strtoul ( p , & newp , 10 ) ;
2007-10-07 02:28:14 +04:00
if ( newp [ 0 ] ! = ' . ' ) return false ;
2006-12-19 22:25:49 +03:00
p = newp + 1 ;
2003-08-13 05:53:07 +04:00
2016-01-11 23:38:20 +03:00
/*the ber representation can't use more space than the string one */
2009-10-05 05:46:20 +04:00
* blob = data_blob_talloc ( mem_ctx , NULL , strlen ( OID ) ) ;
2007-10-07 02:28:14 +04:00
if ( ! blob - > data ) return false ;
2006-12-20 18:51:02 +03:00
blob - > data [ 0 ] = 40 * v + v2 ;
i = 1 ;
2003-08-13 05:53:07 +04:00
while ( * p ) {
2010-10-20 14:45:59 +04:00
if ( ! isdigit ( * p ) ) return false ;
2006-12-19 22:25:49 +03:00
v = strtoul ( p , & newp , 10 ) ;
if ( newp [ 0 ] = = ' . ' ) {
p = newp + 1 ;
2010-10-20 14:45:59 +04:00
/* check for empty last component */
if ( ! * p ) return false ;
2006-12-19 22:25:49 +03:00
} else if ( newp [ 0 ] = = ' \0 ' ) {
p = newp ;
} else {
2006-12-20 18:51:02 +03:00
data_blob_free ( blob ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-12-19 22:25:49 +03:00
}
2006-12-20 18:51:02 +03:00
if ( v > = ( 1 < < 28 ) ) blob - > data [ i + + ] = ( 0x80 | ( ( v > > 28 ) & 0x7f ) ) ;
if ( v > = ( 1 < < 21 ) ) blob - > data [ i + + ] = ( 0x80 | ( ( v > > 21 ) & 0x7f ) ) ;
if ( v > = ( 1 < < 14 ) ) blob - > data [ i + + ] = ( 0x80 | ( ( v > > 14 ) & 0x7f ) ) ;
if ( v > = ( 1 < < 7 ) ) blob - > data [ i + + ] = ( 0x80 | ( ( v > > 7 ) & 0x7f ) ) ;
blob - > data [ i + + ] = ( v & 0x7f ) ;
2003-08-13 05:53:07 +04:00
}
2006-12-19 22:25:49 +03:00
2006-12-20 18:51:02 +03:00
blob - > length = i ;
2007-10-07 02:28:14 +04:00
return true ;
2006-12-19 22:25:49 +03:00
}
2009-09-25 17:38:54 +04:00
/**
* Serialize partial OID string .
* Partial OIDs are in the form :
* 1 : 2.5 .6 : 0x81
* 1 : 2.5 .6 : 0x8182
*/
2009-10-05 05:46:20 +04:00
bool ber_write_partial_OID_String ( TALLOC_CTX * mem_ctx , DATA_BLOB * blob , const char * partial_oid )
2009-09-25 17:38:54 +04:00
{
2009-10-05 05:46:20 +04:00
TALLOC_CTX * tmp_ctx = talloc_new ( mem_ctx ) ;
char * oid = talloc_strdup ( tmp_ctx , partial_oid ) ;
2009-09-25 17:38:54 +04:00
char * p ;
/* truncate partial part so ber_write_OID_String() works */
p = strchr ( oid , ' : ' ) ;
if ( p ) {
* p = ' \0 ' ;
p + + ;
}
2009-10-05 05:46:20 +04:00
if ( ! ber_write_OID_String ( mem_ctx , blob , oid ) ) {
talloc_free ( tmp_ctx ) ;
2009-09-25 17:38:54 +04:00
return false ;
}
2010-10-18 04:49:21 +04:00
/* Add partially encoded sub-identifier */
2009-09-25 17:38:54 +04:00
if ( p ) {
2009-10-05 05:46:20 +04:00
DATA_BLOB tmp_blob = strhex_to_data_blob ( tmp_ctx , p ) ;
2011-04-22 11:41:52 +04:00
if ( ! data_blob_append ( mem_ctx , blob , tmp_blob . data ,
tmp_blob . length ) ) {
talloc_free ( tmp_ctx ) ;
return false ;
}
2009-09-25 17:38:54 +04:00
}
2009-10-05 05:46:20 +04:00
talloc_free ( tmp_ctx ) ;
2009-09-25 17:38:54 +04:00
return true ;
}
2006-12-19 22:25:49 +03:00
/* write an object ID to a ASN1 buffer */
2007-10-07 02:28:14 +04:00
bool asn1_write_OID ( struct asn1_data * data , const char * OID )
2006-12-19 22:25:49 +03:00
{
2006-12-20 18:51:02 +03:00
DATA_BLOB blob ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_push_tag ( data , ASN1_OID ) ) return false ;
2006-12-20 18:51:02 +03:00
2009-10-05 05:46:20 +04:00
if ( ! ber_write_OID_String ( NULL , & blob , OID ) ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2006-12-20 18:51:02 +03:00
}
if ( ! asn1_write ( data , blob . data , blob . length ) ) {
2009-07-30 10:29:28 +04:00
data_blob_free ( & blob ) ;
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2006-12-20 18:51:02 +03:00
}
data_blob_free ( & blob ) ;
2003-08-13 05:53:07 +04:00
return asn1_pop_tag ( data ) ;
}
/* write an octet string */
2007-10-07 02:28:14 +04:00
bool asn1_write_OctetString ( struct asn1_data * data , const void * p , size_t length )
2003-08-13 05:53:07 +04:00
{
2014-09-19 00:58:45 +04:00
if ( ! asn1_push_tag ( data , ASN1_OCTET_STRING ) ) return false ;
if ( ! asn1_write ( data , p , length ) ) return false ;
return asn1_pop_tag ( data ) ;
2003-08-13 05:53:07 +04:00
}
2005-06-14 07:52:27 +04:00
/* write a LDAP string */
2007-10-07 02:28:14 +04:00
bool asn1_write_LDAPString ( struct asn1_data * data , const char * s )
2005-06-14 07:52:27 +04:00
{
2014-09-19 00:58:45 +04:00
return asn1_write ( data , s , strlen ( s ) ) ;
2005-06-14 07:52:27 +04:00
}
2007-12-27 16:47:11 +03:00
/* write a LDAP string from a DATA_BLOB */
bool asn1_write_DATA_BLOB_LDAPString ( struct asn1_data * data , const DATA_BLOB * s )
{
2014-09-19 00:58:45 +04:00
return asn1_write ( data , s - > data , s - > length ) ;
2007-12-27 16:47:11 +03:00
}
2003-08-13 05:53:07 +04:00
/* write a general string */
2007-10-07 02:28:14 +04:00
bool asn1_write_GeneralString ( struct asn1_data * data , const char * s )
2003-08-13 05:53:07 +04:00
{
2014-09-19 00:58:45 +04:00
if ( ! asn1_push_tag ( data , ASN1_GENERAL_STRING ) ) return false ;
if ( ! asn1_write_LDAPString ( data , s ) ) return false ;
return asn1_pop_tag ( data ) ;
2003-08-13 05:53:07 +04:00
}
2007-10-07 02:28:14 +04:00
bool asn1_write_ContextSimple ( struct asn1_data * data , uint8_t num , DATA_BLOB * blob )
2004-08-17 15:22:44 +04:00
{
2014-09-19 00:58:45 +04:00
if ( ! asn1_push_tag ( data , ASN1_CONTEXT_SIMPLE ( num ) ) ) return false ;
if ( ! asn1_write ( data , blob - > data , blob - > length ) ) return false ;
return asn1_pop_tag ( data ) ;
2004-08-17 15:22:44 +04:00
}
2003-08-13 05:53:07 +04:00
/* write a BOOLEAN */
2007-10-07 02:28:14 +04:00
bool asn1_write_BOOLEAN ( struct asn1_data * data , bool v )
2003-08-13 05:53:07 +04:00
{
2014-09-19 00:58:45 +04:00
if ( ! asn1_push_tag ( data , ASN1_BOOLEAN ) ) return false ;
if ( ! asn1_write_uint8 ( data , v ? 0xFF : 0 ) ) return false ;
return asn1_pop_tag ( data ) ;
2003-08-13 05:53:07 +04:00
}
2007-10-07 02:28:14 +04:00
bool asn1_read_BOOLEAN ( struct asn1_data * data , bool * v )
2004-08-12 08:55:59 +04:00
{
2004-10-10 03:58:11 +04:00
uint8_t tmp = 0 ;
2014-09-19 00:58:45 +04:00
if ( ! asn1_start_tag ( data , ASN1_BOOLEAN ) ) return false ;
* v = false ;
if ( ! asn1_read_uint8 ( data , & tmp ) ) return false ;
2004-10-10 03:58:11 +04:00
if ( tmp = = 0xFF ) {
2007-10-07 02:28:14 +04:00
* v = true ;
2004-10-10 03:58:11 +04:00
}
2014-09-19 00:58:45 +04:00
return asn1_end_tag ( data ) ;
2004-08-12 08:55:59 +04:00
}
2009-06-10 05:44:47 +04:00
/* write a BOOLEAN in a simple context */
bool asn1_write_BOOLEAN_context ( struct asn1_data * data , bool v , int context )
{
2014-09-19 00:58:45 +04:00
if ( ! asn1_push_tag ( data , ASN1_CONTEXT_SIMPLE ( context ) ) ) return false ;
if ( ! asn1_write_uint8 ( data , v ? 0xFF : 0 ) ) return false ;
return asn1_pop_tag ( data ) ;
2009-06-10 05:44:47 +04:00
}
bool asn1_read_BOOLEAN_context ( struct asn1_data * data , bool * v , int context )
{
uint8_t tmp = 0 ;
2014-09-19 00:58:45 +04:00
if ( ! asn1_start_tag ( data , ASN1_CONTEXT_SIMPLE ( context ) ) ) return false ;
* v = false ;
if ( ! asn1_read_uint8 ( data , & tmp ) ) return false ;
2009-06-10 05:44:47 +04:00
if ( tmp = = 0xFF ) {
* v = true ;
}
2014-09-19 00:58:45 +04:00
return asn1_end_tag ( data ) ;
2009-06-10 05:44:47 +04:00
}
2003-08-13 05:53:07 +04:00
/* check a BOOLEAN */
2007-10-07 02:28:14 +04:00
bool asn1_check_BOOLEAN ( struct asn1_data * data , bool v )
2003-08-13 05:53:07 +04:00
{
2004-05-25 21:50:17 +04:00
uint8_t b = 0 ;
2003-08-13 05:53:07 +04:00
2014-09-19 00:58:45 +04:00
if ( ! asn1_read_uint8 ( data , & b ) ) return false ;
2003-08-13 05:53:07 +04:00
if ( b ! = ASN1_BOOLEAN ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
2014-09-19 00:58:45 +04:00
if ( ! asn1_read_uint8 ( data , & b ) ) return false ;
2003-08-13 05:53:07 +04:00
if ( b ! = v ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
return ! data - > has_error ;
}
2004-11-02 09:42:15 +03:00
/* load a struct asn1_data structure with a lump of data, ready to be parsed */
2007-10-07 02:28:14 +04:00
bool asn1_load ( struct asn1_data * data , DATA_BLOB blob )
2003-08-13 05:53:07 +04:00
{
ZERO_STRUCTP ( data ) ;
2008-10-22 16:02:31 +04:00
data - > data = ( uint8_t * ) talloc_memdup ( data , blob . data , blob . length ) ;
2003-08-13 05:53:07 +04:00
if ( ! data - > data ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
data - > length = blob . length ;
2007-10-07 02:28:14 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2004-08-12 08:55:59 +04:00
/* Peek into an ASN1 buffer, not advancing the pointer */
2007-10-07 02:28:14 +04:00
bool asn1_peek ( struct asn1_data * data , void * p , int len )
2003-08-13 05:53:07 +04:00
{
2007-09-18 17:31:05 +04:00
if ( data - > has_error )
2007-10-07 02:28:14 +04:00
return false ;
2007-09-18 17:31:05 +04:00
2004-08-12 08:55:59 +04:00
if ( len < 0 | | data - > ofs + len < data - > ofs | | data - > ofs + len < len )
2007-10-07 02:28:14 +04:00
return false ;
2004-06-19 12:15:41 +04:00
2005-06-19 14:37:45 +04:00
if ( data - > ofs + len > data - > length ) {
/* we need to mark the buffer as consumed, so the caller knows
this was an out of data error , and not a decode error */
data - > ofs = data - > length ;
2007-10-07 02:28:14 +04:00
return false ;
2005-06-19 14:37:45 +04:00
}
2004-08-12 08:55:59 +04:00
2003-08-13 05:53:07 +04:00
memcpy ( p , data - > data + data - > ofs , len ) ;
2007-10-07 02:28:14 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2004-07-06 05:28:12 +04:00
/* read from a ASN1 buffer, advancing the buffer pointer */
2007-10-07 02:28:14 +04:00
bool asn1_read ( struct asn1_data * data , void * p , int len )
2004-07-06 05:28:12 +04:00
{
2004-08-12 08:55:59 +04:00
if ( ! asn1_peek ( data , p , len ) ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2004-07-06 05:28:12 +04:00
}
2004-08-12 08:55:59 +04:00
data - > ofs + = len ;
2007-10-07 02:28:14 +04:00
return true ;
2004-07-06 05:28:12 +04:00
}
/* read a uint8_t from a ASN1 buffer */
2007-10-07 02:28:14 +04:00
bool asn1_read_uint8 ( struct asn1_data * data , uint8_t * v )
2004-08-12 08:55:59 +04:00
{
return asn1_read ( data , v , 1 ) ;
}
2007-10-07 02:28:14 +04:00
bool asn1_peek_uint8 ( struct asn1_data * data , uint8_t * v )
2004-07-06 05:28:12 +04:00
{
return asn1_peek ( data , v , 1 ) ;
}
2007-10-07 02:28:14 +04:00
bool asn1_peek_tag ( struct asn1_data * data , uint8_t tag )
2004-08-12 08:55:59 +04:00
{
uint8_t b ;
2004-08-17 14:04:25 +04:00
if ( asn1_tag_remaining ( data ) < = 0 ) {
2007-10-07 02:28:14 +04:00
return false ;
2004-08-17 14:04:25 +04:00
}
2007-09-18 17:31:05 +04:00
if ( ! asn1_peek_uint8 ( data , & b ) )
2007-10-07 02:28:14 +04:00
return false ;
2004-08-12 08:55:59 +04:00
return ( b = = tag ) ;
}
2010-09-23 20:10:28 +04:00
/*
* just get the needed size the tag would consume
*/
2016-01-11 23:41:22 +03:00
static bool asn1_peek_tag_needed_size ( struct asn1_data * data , uint8_t tag ,
size_t * size )
2010-09-23 20:10:28 +04:00
{
off_t start_ofs = data - > ofs ;
uint8_t b ;
size_t taglen = 0 ;
if ( data - > has_error ) {
return false ;
}
if ( ! asn1_read_uint8 ( data , & b ) ) {
data - > ofs = start_ofs ;
data - > has_error = false ;
return false ;
}
if ( b ! = tag ) {
data - > ofs = start_ofs ;
data - > has_error = false ;
return false ;
}
if ( ! asn1_read_uint8 ( data , & b ) ) {
data - > ofs = start_ofs ;
data - > has_error = false ;
return false ;
}
if ( b & 0x80 ) {
int n = b & 0x7f ;
if ( ! asn1_read_uint8 ( data , & b ) ) {
data - > ofs = start_ofs ;
data - > has_error = false ;
return false ;
}
2010-10-02 12:03:55 +04:00
if ( n > 4 ) {
/*
* We should not allow more than 4 bytes
* for the encoding of the tag length .
*
* Otherwise we ' d overflow the taglen
* variable on 32 bit systems .
*/
data - > ofs = start_ofs ;
data - > has_error = false ;
return false ;
}
2010-09-23 20:10:28 +04:00
taglen = b ;
while ( n > 1 ) {
if ( ! asn1_read_uint8 ( data , & b ) ) {
data - > ofs = start_ofs ;
data - > has_error = false ;
return false ;
}
taglen = ( taglen < < 8 ) | b ;
n - - ;
}
} else {
taglen = b ;
}
* size = ( data - > ofs - start_ofs ) + taglen ;
data - > ofs = start_ofs ;
data - > has_error = false ;
return true ;
}
2003-08-13 05:53:07 +04:00
/* start reading a nested asn1 structure */
2007-10-07 02:28:14 +04:00
bool asn1_start_tag ( struct asn1_data * data , uint8_t tag )
2003-08-13 05:53:07 +04:00
{
2004-05-25 21:50:17 +04:00
uint8_t b ;
2003-08-13 05:53:07 +04:00
struct nesting * nesting ;
2016-01-31 13:12:23 +03:00
2003-08-13 05:53:07 +04:00
if ( ! asn1_read_uint8 ( data , & b ) )
2007-10-07 02:28:14 +04:00
return false ;
2003-08-13 05:53:07 +04:00
if ( b ! = tag ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
2007-05-21 10:12:06 +04:00
nesting = talloc ( data , struct nesting ) ;
2003-08-13 05:53:07 +04:00
if ( ! nesting ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
if ( ! asn1_read_uint8 ( data , & b ) ) {
2007-10-07 02:28:14 +04:00
return false ;
2003-08-13 05:53:07 +04:00
}
if ( b & 0x80 ) {
int n = b & 0x7f ;
if ( ! asn1_read_uint8 ( data , & b ) )
2007-10-07 02:28:14 +04:00
return false ;
2003-08-13 05:53:07 +04:00
nesting - > taglen = b ;
while ( n > 1 ) {
2016-01-31 13:12:23 +03:00
if ( ! asn1_read_uint8 ( data , & b ) )
2007-10-07 02:28:14 +04:00
return false ;
2003-08-13 05:53:07 +04:00
nesting - > taglen = ( nesting - > taglen < < 8 ) | b ;
n - - ;
}
} else {
nesting - > taglen = b ;
}
nesting - > start = data - > ofs ;
nesting - > next = data - > nesting ;
data - > nesting = nesting ;
2006-09-29 08:45:15 +04:00
if ( asn1_tag_remaining ( data ) = = - 1 ) {
2007-10-07 02:28:14 +04:00
return false ;
2006-09-29 08:45:15 +04:00
}
2003-08-13 05:53:07 +04:00
return ! data - > has_error ;
}
/* stop reading a tag */
2007-10-07 02:28:14 +04:00
bool asn1_end_tag ( struct asn1_data * data )
2003-08-13 05:53:07 +04:00
{
struct nesting * nesting ;
/* make sure we read it all */
if ( asn1_tag_remaining ( data ) ! = 0 ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
nesting = data - > nesting ;
if ( ! nesting ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
data - > nesting = nesting - > next ;
2004-08-25 06:05:02 +04:00
talloc_free ( nesting ) ;
2007-10-07 02:28:14 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
/* work out how many bytes are left in this nested tag */
2004-11-02 09:42:15 +03:00
int asn1_tag_remaining ( struct asn1_data * data )
2003-08-13 05:53:07 +04:00
{
2006-09-29 08:45:15 +04:00
int remaining ;
if ( data - > has_error ) {
return - 1 ;
}
2003-08-13 05:53:07 +04:00
if ( ! data - > nesting ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
2003-08-13 05:53:07 +04:00
return - 1 ;
}
2006-09-29 08:45:15 +04:00
remaining = data - > nesting - > taglen - ( data - > ofs - data - > nesting - > start ) ;
if ( remaining > ( data - > length - data - > ofs ) ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
2006-09-29 08:45:15 +04:00
return - 1 ;
}
return remaining ;
2003-08-13 05:53:07 +04:00
}
2009-09-25 18:28:33 +04:00
/**
* Internal implementation for reading binary OIDs
* Reading is done as far in the buffer as valid OID
* till buffer ends or not valid sub - identifier is found .
*/
static bool _ber_read_OID_String_impl ( TALLOC_CTX * mem_ctx , DATA_BLOB blob ,
2010-12-15 19:02:49 +03:00
char * * OID , size_t * bytes_eaten )
2009-09-25 18:28:33 +04:00
{
int i ;
uint8_t * b ;
2010-01-05 20:40:54 +03:00
unsigned int v ;
2009-09-25 18:28:33 +04:00
char * tmp_oid = NULL ;
if ( blob . length < 2 ) return false ;
b = blob . data ;
2016-01-12 00:05:43 +03:00
tmp_oid = talloc_asprintf ( mem_ctx , " %u.%u " , b [ 0 ] / 40 , b [ 0 ] % 40 ) ;
2009-09-25 18:28:33 +04:00
if ( ! tmp_oid ) goto nomem ;
2010-03-21 22:59:13 +03:00
if ( bytes_eaten ! = NULL ) {
* bytes_eaten = 0 ;
}
2009-09-25 18:28:33 +04:00
for ( i = 1 , v = 0 ; i < blob . length ; i + + ) {
v = ( v < < 7 ) | ( b [ i ] & 0x7f ) ;
if ( ! ( b [ i ] & 0x80 ) ) {
tmp_oid = talloc_asprintf_append_buffer ( tmp_oid , " .%u " , v ) ;
v = 0 ;
if ( bytes_eaten )
* bytes_eaten = i + 1 ;
}
if ( ! tmp_oid ) goto nomem ;
}
* OID = tmp_oid ;
return true ;
nomem :
return false ;
}
2006-12-20 18:51:02 +03:00
/* read an object ID from a data blob */
2010-12-15 19:02:49 +03:00
bool ber_read_OID_String ( TALLOC_CTX * mem_ctx , DATA_BLOB blob , char * * OID )
2003-08-13 05:53:07 +04:00
{
2009-09-26 02:41:18 +04:00
size_t bytes_eaten ;
2003-08-13 05:53:07 +04:00
2009-09-26 02:41:18 +04:00
if ( ! _ber_read_OID_String_impl ( mem_ctx , blob , OID , & bytes_eaten ) )
2007-10-07 02:28:14 +04:00
return false ;
2003-08-13 05:53:07 +04:00
2009-09-26 02:41:18 +04:00
return ( bytes_eaten = = blob . length ) ;
2006-12-19 22:25:49 +03:00
}
2003-08-13 05:53:07 +04:00
2009-09-25 18:29:05 +04:00
/**
* Deserialize partial OID string .
* Partial OIDs are in the form :
* 1 : 2.5 .6 : 0x81
* 1 : 2.5 .6 : 0x8182
*/
2010-12-15 19:02:49 +03:00
bool ber_read_partial_OID_String ( TALLOC_CTX * mem_ctx , DATA_BLOB blob ,
char * * partial_oid )
2009-09-25 18:29:05 +04:00
{
size_t bytes_left ;
size_t bytes_eaten ;
char * identifier = NULL ;
char * tmp_oid = NULL ;
2010-12-15 19:02:49 +03:00
if ( ! _ber_read_OID_String_impl ( mem_ctx , blob , & tmp_oid , & bytes_eaten ) )
2009-09-25 18:29:05 +04:00
return false ;
if ( bytes_eaten < blob . length ) {
bytes_left = blob . length - bytes_eaten ;
identifier = hex_encode_talloc ( mem_ctx , & blob . data [ bytes_eaten ] , bytes_left ) ;
if ( ! identifier ) goto nomem ;
* partial_oid = talloc_asprintf_append_buffer ( tmp_oid , " :0x%s " , identifier ) ;
if ( ! * partial_oid ) goto nomem ;
TALLOC_FREE ( identifier ) ;
} else {
* partial_oid = tmp_oid ;
}
return true ;
nomem :
TALLOC_FREE ( identifier ) ;
TALLOC_FREE ( tmp_oid ) ;
return false ;
}
2006-12-19 22:25:49 +03:00
/* read an object ID from a ASN1 buffer */
2010-12-15 19:02:49 +03:00
bool asn1_read_OID ( struct asn1_data * data , TALLOC_CTX * mem_ctx , char * * OID )
2006-12-19 22:25:49 +03:00
{
2006-12-20 18:51:02 +03:00
DATA_BLOB blob ;
int len ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_start_tag ( data , ASN1_OID ) ) return false ;
2006-12-20 18:51:02 +03:00
len = asn1_tag_remaining ( data ) ;
if ( len < 0 ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2006-12-20 18:51:02 +03:00
}
blob = data_blob ( NULL , len ) ;
if ( ! blob . data ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2006-12-20 18:51:02 +03:00
}
2014-09-19 00:58:45 +04:00
if ( ! asn1_read ( data , blob . data , len ) ) return false ;
if ( ! asn1_end_tag ( data ) ) {
2006-12-20 18:51:02 +03:00
data_blob_free ( & blob ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-12-19 22:25:49 +03:00
}
2006-12-20 18:51:02 +03:00
2007-05-21 10:12:06 +04:00
if ( ! ber_read_OID_String ( mem_ctx , blob , OID ) ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
2006-12-20 18:51:02 +03:00
data_blob_free ( & blob ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-12-20 18:51:02 +03:00
}
data_blob_free ( & blob ) ;
2007-10-07 02:28:14 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
/* check that the next object ID is correct */
2007-10-07 02:28:14 +04:00
bool asn1_check_OID ( struct asn1_data * data , const char * OID )
2003-08-13 05:53:07 +04:00
{
2010-12-15 19:02:49 +03:00
char * id ;
2003-08-13 05:53:07 +04:00
2007-10-07 02:28:14 +04:00
if ( ! asn1_read_OID ( data , data , & id ) ) return false ;
2003-08-13 05:53:07 +04:00
if ( strcmp ( id , OID ) ! = 0 ) {
2010-12-15 19:02:49 +03:00
talloc_free ( id ) ;
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
2010-12-15 19:02:49 +03:00
talloc_free ( id ) ;
2007-10-07 02:28:14 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2005-06-14 07:52:27 +04:00
/* read a LDAPString from a ASN1 buffer */
2007-10-07 02:28:14 +04:00
bool asn1_read_LDAPString ( struct asn1_data * data , TALLOC_CTX * mem_ctx , char * * s )
2003-08-13 05:53:07 +04:00
{
int len ;
len = asn1_tag_remaining ( data ) ;
2004-06-19 12:15:41 +04:00
if ( len < 0 ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2004-06-19 12:15:41 +04:00
}
2007-09-07 19:08:14 +04:00
* s = talloc_array ( mem_ctx , char , len + 1 ) ;
2003-08-13 05:53:07 +04:00
if ( ! * s ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2003-08-13 05:53:07 +04:00
}
( * s ) [ len ] = 0 ;
2014-09-19 00:58:45 +04:00
return asn1_read ( data , * s , len ) ;
2003-08-13 05:53:07 +04:00
}
2005-06-14 07:52:27 +04:00
/* read a GeneralString from a ASN1 buffer */
2007-10-07 02:28:14 +04:00
bool asn1_read_GeneralString ( struct asn1_data * data , TALLOC_CTX * mem_ctx , char * * s )
2005-06-14 07:52:27 +04:00
{
2007-10-07 02:28:14 +04:00
if ( ! asn1_start_tag ( data , ASN1_GENERAL_STRING ) ) return false ;
if ( ! asn1_read_LDAPString ( data , mem_ctx , s ) ) return false ;
2005-06-14 07:52:27 +04:00
return asn1_end_tag ( data ) ;
}
2003-08-13 05:53:07 +04:00
/* read a octet string blob */
2007-10-07 02:28:14 +04:00
bool asn1_read_OctetString ( struct asn1_data * data , TALLOC_CTX * mem_ctx , DATA_BLOB * blob )
2003-08-13 05:53:07 +04:00
{
int len ;
ZERO_STRUCTP ( blob ) ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_start_tag ( data , ASN1_OCTET_STRING ) ) return false ;
2003-08-13 05:53:07 +04:00
len = asn1_tag_remaining ( data ) ;
2004-06-19 12:15:41 +04:00
if ( len < 0 ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2004-06-19 12:15:41 +04:00
}
2007-05-21 10:12:06 +04:00
* blob = data_blob_talloc ( mem_ctx , NULL , len + 1 ) ;
2012-07-13 09:42:08 +04:00
if ( ! blob - > data | | blob - > length < len ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2006-09-29 08:45:15 +04:00
}
2014-09-19 00:58:45 +04:00
if ( ! asn1_read ( data , blob - > data , len ) ) goto err ;
if ( ! asn1_end_tag ( data ) ) goto err ;
2005-06-13 13:10:17 +04:00
blob - > length - - ;
blob - > data [ len ] = 0 ;
2007-10-07 02:28:14 +04:00
return true ;
2014-09-19 00:58:45 +04:00
err :
data_blob_free ( blob ) ;
* blob = data_blob_null ;
return false ;
2003-08-13 05:53:07 +04:00
}
2007-10-07 02:28:14 +04:00
bool asn1_read_ContextSimple ( struct asn1_data * data , uint8_t num , DATA_BLOB * blob )
2004-08-17 15:22:44 +04:00
{
int len ;
ZERO_STRUCTP ( blob ) ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_start_tag ( data , ASN1_CONTEXT_SIMPLE ( num ) ) ) return false ;
2004-08-17 15:22:44 +04:00
len = asn1_tag_remaining ( data ) ;
if ( len < 0 ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2004-08-17 15:22:44 +04:00
}
* blob = data_blob ( NULL , len ) ;
2006-12-22 00:14:53 +03:00
if ( ( len ! = 0 ) & & ( ! blob - > data ) ) {
2007-10-07 02:28:14 +04:00
data - > has_error = true ;
return false ;
2006-09-29 08:45:15 +04:00
}
2014-09-19 00:58:45 +04:00
if ( ! asn1_read ( data , blob - > data , len ) ) return false ;
return asn1_end_tag ( data ) ;
2004-08-17 15:22:44 +04:00
}
2008-01-08 23:27:40 +03:00
/* read an integer without tag*/
2007-10-07 02:28:14 +04:00
bool asn1_read_implicit_Integer ( struct asn1_data * data , int * i )
2003-08-13 05:53:07 +04:00
{
2004-05-25 21:50:17 +04:00
uint8_t b ;
2011-05-24 23:47:31 +04:00
bool first_byte = true ;
2003-08-13 05:53:07 +04:00
* i = 0 ;
2004-09-29 16:40:30 +04:00
2005-06-19 14:37:45 +04:00
while ( ! data - > has_error & & asn1_tag_remaining ( data ) > 0 ) {
2007-10-07 02:28:14 +04:00
if ( ! asn1_read_uint8 ( data , & b ) ) return false ;
2011-05-24 23:47:31 +04:00
if ( first_byte ) {
if ( b & 0x80 ) {
/* Number is negative.
Set i to - 1 for sign extend . */
* i = - 1 ;
}
first_byte = false ;
}
2003-08-13 05:53:07 +04:00
* i = ( * i < < 8 ) + b ;
}
2016-01-31 13:12:23 +03:00
return ! data - > has_error ;
2004-09-29 16:40:30 +04:00
}
2008-01-08 23:27:40 +03:00
/* read an integer */
2007-10-07 02:28:14 +04:00
bool asn1_read_Integer ( struct asn1_data * data , int * i )
2004-09-29 16:40:30 +04:00
{
* i = 0 ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_start_tag ( data , ASN1_INTEGER ) ) return false ;
if ( ! asn1_read_implicit_Integer ( data , i ) ) return false ;
2016-01-31 13:12:23 +03:00
return asn1_end_tag ( data ) ;
2003-08-13 05:53:07 +04:00
}
2009-08-13 10:12:01 +04:00
/* read a BIT STRING */
bool asn1_read_BitString ( struct asn1_data * data , TALLOC_CTX * mem_ctx , DATA_BLOB * blob , uint8_t * padding )
{
int len ;
ZERO_STRUCTP ( blob ) ;
if ( ! asn1_start_tag ( data , ASN1_BIT_STRING ) ) return false ;
len = asn1_tag_remaining ( data ) ;
if ( len < 0 ) {
data - > has_error = true ;
return false ;
}
if ( ! asn1_read_uint8 ( data , padding ) ) return false ;
2012-07-13 09:42:08 +04:00
* blob = data_blob_talloc ( mem_ctx , NULL , len + 1 ) ;
if ( ! blob - > data | | blob - > length < len ) {
2009-08-13 10:12:01 +04:00
data - > has_error = true ;
return false ;
}
if ( asn1_read ( data , blob - > data , len - 1 ) ) {
blob - > length - - ;
blob - > data [ len ] = 0 ;
asn1_end_tag ( data ) ;
}
if ( data - > has_error ) {
data_blob_free ( blob ) ;
* blob = data_blob_null ;
* padding = 0 ;
return false ;
}
return true ;
}
2008-01-08 23:27:40 +03:00
/* read an integer */
2007-10-07 02:28:14 +04:00
bool asn1_read_enumerated ( struct asn1_data * data , int * v )
2004-08-12 08:55:59 +04:00
{
* v = 0 ;
2016-01-31 13:12:23 +03:00
2007-10-07 02:28:14 +04:00
if ( ! asn1_start_tag ( data , ASN1_ENUMERATED ) ) return false ;
2005-06-19 14:37:45 +04:00
while ( ! data - > has_error & & asn1_tag_remaining ( data ) > 0 ) {
2004-08-12 08:55:59 +04:00
uint8_t b ;
2015-03-18 10:47:37 +03:00
if ( ! asn1_read_uint8 ( data , & b ) ) {
return false ;
}
2004-08-12 08:55:59 +04:00
* v = ( * v < < 8 ) + b ;
}
2016-01-31 13:12:23 +03:00
return asn1_end_tag ( data ) ;
2004-08-12 08:55:59 +04:00
}
2008-01-08 23:27:40 +03:00
/* check a enumerated value is correct */
2007-10-07 02:28:14 +04:00
bool asn1_check_enumerated ( struct asn1_data * data , int v )
2003-08-13 05:53:07 +04:00
{
2004-05-25 21:50:17 +04:00
uint8_t b ;
2007-10-07 02:28:14 +04:00
if ( ! asn1_start_tag ( data , ASN1_ENUMERATED ) ) return false ;
2014-09-19 00:58:45 +04:00
if ( ! asn1_read_uint8 ( data , & b ) ) return false ;
if ( ! asn1_end_tag ( data ) ) return false ;
2003-08-13 05:53:07 +04:00
if ( v ! = b )
2007-10-07 02:28:14 +04:00
data - > has_error = false ;
2003-08-13 05:53:07 +04:00
return ! data - > has_error ;
}
2008-01-08 23:27:40 +03:00
/* write an enumerated value to the stream */
2007-10-07 02:28:14 +04:00
bool asn1_write_enumerated ( struct asn1_data * data , uint8_t v )
2003-08-13 05:53:07 +04:00
{
2007-10-07 02:28:14 +04:00
if ( ! asn1_push_tag ( data , ASN1_ENUMERATED ) ) return false ;
2014-09-19 00:58:45 +04:00
if ( ! asn1_write_uint8 ( data , v ) ) return false ;
return asn1_pop_tag ( data ) ;
2003-08-13 05:53:07 +04:00
}
2005-11-10 03:28:02 +03:00
2009-06-19 19:39:13 +04:00
/*
Get us the data just written without copying
*/
bool asn1_blob ( const struct asn1_data * asn1 , DATA_BLOB * blob )
{
if ( asn1 - > has_error ) {
return false ;
}
if ( asn1 - > nesting ! = NULL ) {
return false ;
}
blob - > data = asn1 - > data ;
blob - > length = asn1 - > length ;
return true ;
}
2016-01-04 23:53:23 +03:00
bool asn1_extract_blob ( struct asn1_data * asn1 , TALLOC_CTX * mem_ctx ,
DATA_BLOB * pblob )
{
DATA_BLOB blob ;
if ( ! asn1_blob ( asn1 , & blob ) ) {
return false ;
}
* pblob = ( DATA_BLOB ) { . length = blob . length } ;
pblob - > data = talloc_move ( mem_ctx , & blob . data ) ;
/*
* Stop access from here on
*/
asn1 - > has_error = true ;
return true ;
}
2009-06-19 20:20:20 +04:00
/*
Fill in an asn1 struct without making a copy
*/
void asn1_load_nocopy ( struct asn1_data * data , uint8_t * buf , size_t len )
{
ZERO_STRUCTP ( data ) ;
data - > data = buf ;
data - > length = len ;
}
2015-12-21 12:41:39 +03:00
int asn1_peek_full_tag ( DATA_BLOB blob , uint8_t tag , size_t * packet_size )
2010-09-23 20:10:28 +04:00
{
struct asn1_data asn1 ;
2010-10-02 13:13:34 +04:00
size_t size ;
2010-09-23 20:10:28 +04:00
bool ok ;
ZERO_STRUCT ( asn1 ) ;
asn1 . data = blob . data ;
asn1 . length = blob . length ;
ok = asn1_peek_tag_needed_size ( & asn1 , tag , & size ) ;
if ( ! ok ) {
2015-12-21 12:41:39 +03:00
return EMSGSIZE ;
2010-09-23 20:10:28 +04:00
}
if ( size > blob . length ) {
* packet_size = size ;
2015-12-21 12:41:39 +03:00
return EAGAIN ;
2016-01-31 13:12:23 +03:00
}
2005-11-10 03:28:02 +03:00
* packet_size = size ;
2015-12-21 12:41:39 +03:00
return 0 ;
2005-11-10 03:28:02 +03:00
}