2019-05-20 20:08:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2012-09-22 02:30:46 +04:00
/* ASN.1 Object identifier (OID) registry
*
* Copyright ( C ) 2012 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*/
2013-05-04 11:48:27 +04:00
# include <linux/module.h>
2012-09-22 02:30:46 +04:00
# include <linux/export.h>
# include <linux/oid_registry.h>
2012-09-22 02:30:51 +04:00
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/bug.h>
2021-03-17 00:07:36 +03:00
# include <linux/asn1.h>
2012-09-22 02:30:46 +04:00
# include "oid_registry_data.c"
2013-05-04 11:48:27 +04:00
MODULE_DESCRIPTION ( " OID Registry " ) ;
MODULE_AUTHOR ( " Red Hat, Inc. " ) ;
MODULE_LICENSE ( " GPL " ) ;
2012-09-22 02:30:46 +04:00
/**
* look_up_OID - Find an OID registration for the specified data
* @ data : Binary representation of the OID
* @ datasize : Size of the binary representation
*/
enum OID look_up_OID ( const void * data , size_t datasize )
{
const unsigned char * octets = data ;
enum OID oid ;
unsigned char xhash ;
unsigned i , j , k , hash ;
size_t len ;
/* Hash the OID data */
hash = datasize - 1 ;
for ( i = 0 ; i < datasize ; i + + )
hash + = octets [ i ] * 33 ;
hash = ( hash > > 24 ) ^ ( hash > > 16 ) ^ ( hash > > 8 ) ^ hash ;
hash & = 0xff ;
/* Binary search the OID registry. OIDs are stored in ascending order
* of hash value then ascending order of size and then in ascending
* order of reverse value .
*/
i = 0 ;
k = OID__NR ;
while ( i < k ) {
j = ( i + k ) / 2 ;
xhash = oid_search_table [ j ] . hash ;
if ( xhash > hash ) {
k = j ;
continue ;
}
if ( xhash < hash ) {
i = j + 1 ;
continue ;
}
oid = oid_search_table [ j ] . oid ;
len = oid_index [ oid + 1 ] - oid_index [ oid ] ;
if ( len > datasize ) {
k = j ;
continue ;
}
if ( len < datasize ) {
i = j + 1 ;
continue ;
}
/* Variation is most likely to be at the tail end of the
* OID , so do the comparison in reverse .
*/
while ( len > 0 ) {
unsigned char a = oid_data [ oid_index [ oid ] + - - len ] ;
unsigned char b = octets [ len ] ;
if ( a > b ) {
k = j ;
goto next ;
}
if ( a < b ) {
i = j + 1 ;
goto next ;
}
}
return oid ;
next :
;
}
return OID__NR ;
}
EXPORT_SYMBOL_GPL ( look_up_OID ) ;
2012-09-22 02:30:51 +04:00
2021-03-17 00:07:36 +03:00
/**
* parse_OID - Parse an OID from a bytestream
* @ data : Binary representation of the header + OID
* @ datasize : Size of the binary representation
* @ oid : Pointer to oid to return result
*
* Parse an OID from a bytestream that holds the OID in the format
* ASN1_OID | length | oid . The length indicator must equal to datasize - 2.
* - EBADMSG is returned if the bytestream is too short .
*/
int parse_OID ( const void * data , size_t datasize , enum OID * oid )
{
const unsigned char * v = data ;
/* we need 2 bytes of header and at least 1 byte for oid */
if ( datasize < 3 | | v [ 0 ] ! = ASN1_OID | | v [ 1 ] ! = datasize - 2 )
return - EBADMSG ;
* oid = look_up_OID ( data + 2 , datasize - 2 ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( parse_OID ) ;
2012-09-22 02:30:51 +04:00
/*
* sprint_OID - Print an Object Identifier into a buffer
* @ data : The encoded OID to print
* @ datasize : The size of the encoded OID
* @ buffer : The buffer to render into
* @ bufsize : The size of the buffer
*
* The OID is rendered into the buffer in " a.b.c.d " format and the number of
2021-07-08 04:07:31 +03:00
* bytes is returned . - EBADMSG is returned if the data could not be interpreted
2012-09-22 02:30:51 +04:00
* and - ENOBUFS if the buffer was too small .
*/
int sprint_oid ( const void * data , size_t datasize , char * buffer , size_t bufsize )
{
const unsigned char * v = data , * end = v + datasize ;
unsigned long num ;
unsigned char n ;
size_t ret ;
int count ;
if ( v > = end )
2017-12-08 18:13:28 +03:00
goto bad ;
2012-09-22 02:30:51 +04:00
n = * v + + ;
ret = count = snprintf ( buffer , bufsize , " %u.%u " , n / 40 , n % 40 ) ;
2017-12-08 18:13:28 +03:00
if ( count > = bufsize )
return - ENOBUFS ;
2012-09-22 02:30:51 +04:00
buffer + = count ;
bufsize - = count ;
while ( v < end ) {
num = 0 ;
n = * v + + ;
if ( ! ( n & 0x80 ) ) {
num = n ;
} else {
num = n & 0x7f ;
do {
if ( v > = end )
2017-12-08 18:13:28 +03:00
goto bad ;
2012-09-22 02:30:51 +04:00
n = * v + + ;
num < < = 7 ;
num | = n & 0x7f ;
} while ( n & 0x80 ) ;
}
ret + = count = snprintf ( buffer , bufsize , " .%lu " , num ) ;
2017-12-08 18:13:28 +03:00
if ( count > = bufsize )
2012-09-22 02:30:51 +04:00
return - ENOBUFS ;
2017-12-08 18:13:28 +03:00
buffer + = count ;
2017-09-09 02:15:58 +03:00
bufsize - = count ;
2012-09-22 02:30:51 +04:00
}
return ret ;
2017-12-08 18:13:28 +03:00
bad :
snprintf ( buffer , bufsize , " (bad) " ) ;
return - EBADMSG ;
2012-09-22 02:30:51 +04:00
}
EXPORT_SYMBOL_GPL ( sprint_oid ) ;
/**
* sprint_OID - Print an Object Identifier into a buffer
* @ oid : The OID to print
* @ buffer : The buffer to render into
* @ bufsize : The size of the buffer
*
* The OID is rendered into the buffer in " a.b.c.d " format and the number of
* bytes is returned .
*/
int sprint_OID ( enum OID oid , char * buffer , size_t bufsize )
{
int ret ;
BUG_ON ( oid > = OID__NR ) ;
ret = sprint_oid ( oid_data + oid_index [ oid ] ,
oid_index [ oid + 1 ] - oid_index [ oid ] ,
buffer , bufsize ) ;
BUG_ON ( ret = = - EBADMSG ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( sprint_OID ) ;