mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 11:19:37 +00:00
![Stefan Berger](/assets/img/avatar_default.png)
Detect whether a key is an sm2 type of key by its OID in the parameters array rather than assuming that everything under OID_id_ecPublicKey is sm2, which is not the case. Cc: David Howells <dhowells@redhat.com> Cc: keyrings@vger.kernel.org Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> Reviewed-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com> Tested-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
199 lines
4.4 KiB
C
199 lines
4.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/* ASN.1 Object identifier (OID) registry
|
|
*
|
|
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/export.h>
|
|
#include <linux/oid_registry.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/bug.h>
|
|
#include <linux/asn1.h>
|
|
#include "oid_registry_data.c"
|
|
|
|
MODULE_DESCRIPTION("OID Registry");
|
|
MODULE_AUTHOR("Red Hat, Inc.");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
/**
|
|
* 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);
|
|
|
|
/**
|
|
* 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);
|
|
|
|
/*
|
|
* 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
|
|
* bytes is returned. -EBADMSG is returned if the data could not be intepreted
|
|
* 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)
|
|
goto bad;
|
|
|
|
n = *v++;
|
|
ret = count = snprintf(buffer, bufsize, "%u.%u", n / 40, n % 40);
|
|
if (count >= bufsize)
|
|
return -ENOBUFS;
|
|
buffer += count;
|
|
bufsize -= count;
|
|
|
|
while (v < end) {
|
|
num = 0;
|
|
n = *v++;
|
|
if (!(n & 0x80)) {
|
|
num = n;
|
|
} else {
|
|
num = n & 0x7f;
|
|
do {
|
|
if (v >= end)
|
|
goto bad;
|
|
n = *v++;
|
|
num <<= 7;
|
|
num |= n & 0x7f;
|
|
} while (n & 0x80);
|
|
}
|
|
ret += count = snprintf(buffer, bufsize, ".%lu", num);
|
|
if (count >= bufsize)
|
|
return -ENOBUFS;
|
|
buffer += count;
|
|
bufsize -= count;
|
|
}
|
|
|
|
return ret;
|
|
|
|
bad:
|
|
snprintf(buffer, bufsize, "(bad)");
|
|
return -EBADMSG;
|
|
}
|
|
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);
|