Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* ASN.1 Object identifier (OID) registry
0003  *
0004  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/export.h>
0010 #include <linux/oid_registry.h>
0011 #include <linux/kernel.h>
0012 #include <linux/errno.h>
0013 #include <linux/bug.h>
0014 #include <linux/asn1.h>
0015 #include "oid_registry_data.c"
0016 
0017 MODULE_DESCRIPTION("OID Registry");
0018 MODULE_AUTHOR("Red Hat, Inc.");
0019 MODULE_LICENSE("GPL");
0020 
0021 /**
0022  * look_up_OID - Find an OID registration for the specified data
0023  * @data: Binary representation of the OID
0024  * @datasize: Size of the binary representation
0025  */
0026 enum OID look_up_OID(const void *data, size_t datasize)
0027 {
0028     const unsigned char *octets = data;
0029     enum OID oid;
0030     unsigned char xhash;
0031     unsigned i, j, k, hash;
0032     size_t len;
0033 
0034     /* Hash the OID data */
0035     hash = datasize - 1;
0036 
0037     for (i = 0; i < datasize; i++)
0038         hash += octets[i] * 33;
0039     hash = (hash >> 24) ^ (hash >> 16) ^ (hash >> 8) ^ hash;
0040     hash &= 0xff;
0041 
0042     /* Binary search the OID registry.  OIDs are stored in ascending order
0043      * of hash value then ascending order of size and then in ascending
0044      * order of reverse value.
0045      */
0046     i = 0;
0047     k = OID__NR;
0048     while (i < k) {
0049         j = (i + k) / 2;
0050 
0051         xhash = oid_search_table[j].hash;
0052         if (xhash > hash) {
0053             k = j;
0054             continue;
0055         }
0056         if (xhash < hash) {
0057             i = j + 1;
0058             continue;
0059         }
0060 
0061         oid = oid_search_table[j].oid;
0062         len = oid_index[oid + 1] - oid_index[oid];
0063         if (len > datasize) {
0064             k = j;
0065             continue;
0066         }
0067         if (len < datasize) {
0068             i = j + 1;
0069             continue;
0070         }
0071 
0072         /* Variation is most likely to be at the tail end of the
0073          * OID, so do the comparison in reverse.
0074          */
0075         while (len > 0) {
0076             unsigned char a = oid_data[oid_index[oid] + --len];
0077             unsigned char b = octets[len];
0078             if (a > b) {
0079                 k = j;
0080                 goto next;
0081             }
0082             if (a < b) {
0083                 i = j + 1;
0084                 goto next;
0085             }
0086         }
0087         return oid;
0088     next:
0089         ;
0090     }
0091 
0092     return OID__NR;
0093 }
0094 EXPORT_SYMBOL_GPL(look_up_OID);
0095 
0096 /**
0097  * parse_OID - Parse an OID from a bytestream
0098  * @data: Binary representation of the header + OID
0099  * @datasize: Size of the binary representation
0100  * @oid: Pointer to oid to return result
0101  *
0102  * Parse an OID from a bytestream that holds the OID in the format
0103  * ASN1_OID | length | oid. The length indicator must equal to datasize - 2.
0104  * -EBADMSG is returned if the bytestream is too short.
0105  */
0106 int parse_OID(const void *data, size_t datasize, enum OID *oid)
0107 {
0108     const unsigned char *v = data;
0109 
0110     /* we need 2 bytes of header and at least 1 byte for oid */
0111     if (datasize < 3 || v[0] != ASN1_OID || v[1] != datasize - 2)
0112         return -EBADMSG;
0113 
0114     *oid = look_up_OID(data + 2, datasize - 2);
0115     return 0;
0116 }
0117 EXPORT_SYMBOL_GPL(parse_OID);
0118 
0119 /*
0120  * sprint_OID - Print an Object Identifier into a buffer
0121  * @data: The encoded OID to print
0122  * @datasize: The size of the encoded OID
0123  * @buffer: The buffer to render into
0124  * @bufsize: The size of the buffer
0125  *
0126  * The OID is rendered into the buffer in "a.b.c.d" format and the number of
0127  * bytes is returned.  -EBADMSG is returned if the data could not be interpreted
0128  * and -ENOBUFS if the buffer was too small.
0129  */
0130 int sprint_oid(const void *data, size_t datasize, char *buffer, size_t bufsize)
0131 {
0132     const unsigned char *v = data, *end = v + datasize;
0133     unsigned long num;
0134     unsigned char n;
0135     size_t ret;
0136     int count;
0137 
0138     if (v >= end)
0139         goto bad;
0140 
0141     n = *v++;
0142     ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
0143     if (count >= bufsize)
0144         return -ENOBUFS;
0145     buffer += count;
0146     bufsize -= count;
0147 
0148     while (v < end) {
0149         num = 0;
0150         n = *v++;
0151         if (!(n & 0x80)) {
0152             num = n;
0153         } else {
0154             num = n & 0x7f;
0155             do {
0156                 if (v >= end)
0157                     goto bad;
0158                 n = *v++;
0159                 num <<= 7;
0160                 num |= n & 0x7f;
0161             } while (n & 0x80);
0162         }
0163         ret += count = snprintf(buffer, bufsize, ".%lu", num);
0164         if (count >= bufsize)
0165             return -ENOBUFS;
0166         buffer += count;
0167         bufsize -= count;
0168     }
0169 
0170     return ret;
0171 
0172 bad:
0173     snprintf(buffer, bufsize, "(bad)");
0174     return -EBADMSG;
0175 }
0176 EXPORT_SYMBOL_GPL(sprint_oid);
0177 
0178 /**
0179  * sprint_OID - Print an Object Identifier into a buffer
0180  * @oid: The OID to print
0181  * @buffer: The buffer to render into
0182  * @bufsize: The size of the buffer
0183  *
0184  * The OID is rendered into the buffer in "a.b.c.d" format and the number of
0185  * bytes is returned.
0186  */
0187 int sprint_OID(enum OID oid, char *buffer, size_t bufsize)
0188 {
0189     int ret;
0190 
0191     BUG_ON(oid >= OID__NR);
0192 
0193     ret = sprint_oid(oid_data + oid_index[oid],
0194              oid_index[oid + 1] - oid_index[oid],
0195              buffer, bufsize);
0196     BUG_ON(ret == -EBADMSG);
0197     return ret;
0198 }
0199 EXPORT_SYMBOL_GPL(sprint_OID);