mirror of
https://github.com/AsahiLinux/u-boot
synced 2025-03-16 06:46:59 +00:00
Merge branch '2019-12-06-master-imports'
- Allow for the sysboot command, which is used to parse extlinux.conf files to be used without PXE support. There is no functional change here aside from fixing distro boot in a few cases where we actually lacked the ability to parse the extlinux.conf file - Add the x509/pkcs7 parsers from Linux, a pre-requisite to EFI Secure Boot support.
This commit is contained in:
commit
d79ae6aa30
52 changed files with 8643 additions and 1598 deletions
1
Kconfig
1
Kconfig
|
@ -88,6 +88,7 @@ config DISTRO_DEFAULTS
|
|||
select CMD_PART if PARTITIONS
|
||||
select CMD_PING if CMD_NET
|
||||
select CMD_PXE if NET
|
||||
select CMD_SYSBOOT
|
||||
select ENV_VARS_UBOOT_CONFIG
|
||||
select HUSH_PARSER
|
||||
select SUPPORT_RAW_INITRD
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1889,6 +1889,7 @@ checkarmreloc: u-boot
|
|||
fi
|
||||
|
||||
tools/version.h: include/version.h
|
||||
$(Q)mkdir -p $(dir $@)
|
||||
$(call if_changed,copy)
|
||||
|
||||
envtools: scripts_basic $(version_h) $(timestamp_h) tools/version.h
|
||||
|
@ -1957,6 +1958,7 @@ clean: $(clean-dirs)
|
|||
-o -name '*.ko.*' -o -name '*.su' -o -name '*.pyc' \
|
||||
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
|
||||
-o -name '*.lex.c' -o -name '*.tab.[ch]' \
|
||||
-o -name '*.asn1.[ch]' \
|
||||
-o -name '*.symtypes' -o -name 'modules.order' \
|
||||
-o -name modules.builtin -o -name '.tmp_*.o.*' \
|
||||
-o -name 'dsdt.aml' -o -name 'dsdt.asl.tmp' -o -name 'dsdt.c' \
|
||||
|
|
|
@ -1625,6 +1625,7 @@ config CMD_LED
|
|||
config CMD_DATE
|
||||
bool "date"
|
||||
default y if DM_RTC
|
||||
select LIB_DATE
|
||||
help
|
||||
Enable the 'date' command for getting/setting the time/date in RTC
|
||||
devices.
|
||||
|
@ -1671,6 +1672,12 @@ config CMD_SOUND
|
|||
sound init - set up sound system
|
||||
sound play - play a sound
|
||||
|
||||
config CMD_SYSBOOT
|
||||
bool "sysboot"
|
||||
select MENU
|
||||
help
|
||||
Boot image via local extlinux.conf file
|
||||
|
||||
config CMD_QFW
|
||||
bool "qfw"
|
||||
select QFW
|
||||
|
|
|
@ -111,7 +111,7 @@ ifdef CONFIG_PCI
|
|||
obj-$(CONFIG_CMD_PCI) += pci.o
|
||||
endif
|
||||
obj-$(CONFIG_CMD_PINMUX) += pinmux.o
|
||||
obj-$(CONFIG_CMD_PXE) += pxe.o
|
||||
obj-$(CONFIG_CMD_PXE) += pxe.o pxe_utils.o
|
||||
obj-$(CONFIG_CMD_WOL) += wol.o
|
||||
obj-$(CONFIG_CMD_QFW) += qfw.o
|
||||
obj-$(CONFIG_CMD_READ) += read.o
|
||||
|
@ -130,6 +130,7 @@ obj-$(CONFIG_CMD_SETEXPR) += setexpr.o
|
|||
obj-$(CONFIG_CMD_SPI) += spi.o
|
||||
obj-$(CONFIG_CMD_STRINGS) += strings.o
|
||||
obj-$(CONFIG_CMD_SMC) += smccc.o
|
||||
obj-$(CONFIG_CMD_SYSBOOT) += sysboot.o pxe_utils.o
|
||||
obj-$(CONFIG_CMD_TERMINAL) += terminal.o
|
||||
obj-$(CONFIG_CMD_TIME) += time.o
|
||||
obj-$(CONFIG_CMD_TRACE) += trace.o
|
||||
|
|
17
cmd/nvedit.c
17
cmd/nvedit.c
|
@ -681,6 +681,23 @@ char *env_get(const char *name)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like env_get, but prints an error if envvar isn't defined in the
|
||||
* environment. It always returns what env_get does, so it can be used in
|
||||
* place of env_get without changing error handling otherwise.
|
||||
*/
|
||||
char *from_env(const char *envvar)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
ret = env_get(envvar);
|
||||
|
||||
if (!ret)
|
||||
printf("missing environment variable: %s\n", envvar);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up variable from environment for restricted C runtime env.
|
||||
*/
|
||||
|
|
1352
cmd/pxe_utils.c
Normal file
1352
cmd/pxe_utils.c
Normal file
File diff suppressed because it is too large
Load diff
88
cmd/pxe_utils.h
Normal file
88
cmd/pxe_utils.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
|
||||
#ifndef __PXE_UTILS_H
|
||||
#define __PXE_UTILS_H
|
||||
|
||||
/*
|
||||
* A note on the pxe file parser.
|
||||
*
|
||||
* We're parsing files that use syslinux grammar, which has a few quirks.
|
||||
* String literals must be recognized based on context - there is no
|
||||
* quoting or escaping support. There's also nothing to explicitly indicate
|
||||
* when a label section completes. We deal with that by ending a label
|
||||
* section whenever we see a line that doesn't include.
|
||||
*
|
||||
* As with the syslinux family, this same file format could be reused in the
|
||||
* future for non pxe purposes. The only action it takes during parsing that
|
||||
* would throw this off is handling of include files. It assumes we're using
|
||||
* pxe, and does a tftp download of a file listed as an include file in the
|
||||
* middle of the parsing operation. That could be handled by refactoring it to
|
||||
* take a 'include file getter' function.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Describes a single label given in a pxe file.
|
||||
*
|
||||
* Create these with the 'label_create' function given below.
|
||||
*
|
||||
* name - the name of the menu as given on the 'menu label' line.
|
||||
* kernel - the path to the kernel file to use for this label.
|
||||
* append - kernel command line to use when booting this label
|
||||
* initrd - path to the initrd to use for this label.
|
||||
* attempted - 0 if we haven't tried to boot this label, 1 if we have.
|
||||
* localboot - 1 if this label specified 'localboot', 0 otherwise.
|
||||
* list - lets these form a list, which a pxe_menu struct will hold.
|
||||
*/
|
||||
struct pxe_label {
|
||||
char num[4];
|
||||
char *name;
|
||||
char *menu;
|
||||
char *kernel;
|
||||
char *config;
|
||||
char *append;
|
||||
char *initrd;
|
||||
char *fdt;
|
||||
char *fdtdir;
|
||||
int ipappend;
|
||||
int attempted;
|
||||
int localboot;
|
||||
int localboot_val;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/*
|
||||
* Describes a pxe menu as given via pxe files.
|
||||
*
|
||||
* title - the name of the menu as given by a 'menu title' line.
|
||||
* default_label - the name of the default label, if any.
|
||||
* bmp - the bmp file name which is displayed in background
|
||||
* timeout - time in tenths of a second to wait for a user key-press before
|
||||
* booting the default label.
|
||||
* prompt - if 0, don't prompt for a choice unless the timeout period is
|
||||
* interrupted. If 1, always prompt for a choice regardless of
|
||||
* timeout.
|
||||
* labels - a list of labels defined for the menu.
|
||||
*/
|
||||
struct pxe_menu {
|
||||
char *title;
|
||||
char *default_label;
|
||||
char *bmp;
|
||||
int timeout;
|
||||
int prompt;
|
||||
struct list_head labels;
|
||||
};
|
||||
|
||||
extern bool is_pxe;
|
||||
|
||||
extern int (*do_getfile)(cmd_tbl_t *cmdtp, const char *file_path,
|
||||
char *file_addr);
|
||||
void destroy_pxe_menu(struct pxe_menu *cfg);
|
||||
int get_pxe_file(cmd_tbl_t *cmdtp, const char *file_path,
|
||||
unsigned long file_addr);
|
||||
int get_pxelinux_path(cmd_tbl_t *cmdtp, const char *file,
|
||||
unsigned long pxefile_addr_r);
|
||||
void handle_pxe_menu(cmd_tbl_t *cmdtp, struct pxe_menu *cfg);
|
||||
struct pxe_menu *parse_pxefile(cmd_tbl_t *cmdtp, unsigned long menucfg);
|
||||
int format_mac_pxe(char *outbuf, size_t outbuf_len);
|
||||
|
||||
#endif /* __PXE_UTILS_H */
|
134
cmd/sysboot.c
Normal file
134
cmd/sysboot.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <env.h>
|
||||
#include <fs.h>
|
||||
#include "pxe_utils.h"
|
||||
|
||||
static char *fs_argv[5];
|
||||
|
||||
static int do_get_ext2(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
|
||||
{
|
||||
#ifdef CONFIG_CMD_EXT2
|
||||
fs_argv[0] = "ext2load";
|
||||
fs_argv[3] = file_addr;
|
||||
fs_argv[4] = (void *)file_path;
|
||||
|
||||
if (!do_ext2load(cmdtp, 0, 5, fs_argv))
|
||||
return 1;
|
||||
#endif
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int do_get_fat(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
|
||||
{
|
||||
#ifdef CONFIG_CMD_FAT
|
||||
fs_argv[0] = "fatload";
|
||||
fs_argv[3] = file_addr;
|
||||
fs_argv[4] = (void *)file_path;
|
||||
|
||||
if (!do_fat_fsload(cmdtp, 0, 5, fs_argv))
|
||||
return 1;
|
||||
#endif
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int do_get_any(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
|
||||
{
|
||||
#ifdef CONFIG_CMD_FS_GENERIC
|
||||
fs_argv[0] = "load";
|
||||
fs_argv[3] = file_addr;
|
||||
fs_argv[4] = (void *)file_path;
|
||||
|
||||
if (!do_load(cmdtp, 0, 5, fs_argv, FS_TYPE_ANY))
|
||||
return 1;
|
||||
#endif
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Boots a system using a local disk syslinux/extlinux file
|
||||
*
|
||||
* Returns 0 on success, 1 on error.
|
||||
*/
|
||||
static int do_sysboot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
|
||||
{
|
||||
unsigned long pxefile_addr_r;
|
||||
struct pxe_menu *cfg;
|
||||
char *pxefile_addr_str;
|
||||
char *filename;
|
||||
int prompt = 0;
|
||||
|
||||
is_pxe = false;
|
||||
|
||||
if (argc > 1 && strstr(argv[1], "-p")) {
|
||||
prompt = 1;
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc < 4)
|
||||
return cmd_usage(cmdtp);
|
||||
|
||||
if (argc < 5) {
|
||||
pxefile_addr_str = from_env("pxefile_addr_r");
|
||||
if (!pxefile_addr_str)
|
||||
return 1;
|
||||
} else {
|
||||
pxefile_addr_str = argv[4];
|
||||
}
|
||||
|
||||
if (argc < 6) {
|
||||
filename = env_get("bootfile");
|
||||
} else {
|
||||
filename = argv[5];
|
||||
env_set("bootfile", filename);
|
||||
}
|
||||
|
||||
if (strstr(argv[3], "ext2")) {
|
||||
do_getfile = do_get_ext2;
|
||||
} else if (strstr(argv[3], "fat")) {
|
||||
do_getfile = do_get_fat;
|
||||
} else if (strstr(argv[3], "any")) {
|
||||
do_getfile = do_get_any;
|
||||
} else {
|
||||
printf("Invalid filesystem: %s\n", argv[3]);
|
||||
return 1;
|
||||
}
|
||||
fs_argv[1] = argv[1];
|
||||
fs_argv[2] = argv[2];
|
||||
|
||||
if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
|
||||
printf("Invalid pxefile address: %s\n", pxefile_addr_str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (get_pxe_file(cmdtp, filename, pxefile_addr_r) < 0) {
|
||||
printf("Error reading config file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cfg = parse_pxefile(cmdtp, pxefile_addr_r);
|
||||
|
||||
if (!cfg) {
|
||||
printf("Error parsing config file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (prompt)
|
||||
cfg->prompt = 1;
|
||||
|
||||
handle_pxe_menu(cmdtp, cfg);
|
||||
|
||||
destroy_pxe_menu(cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_CMD(sysboot, 7, 1, do_sysboot,
|
||||
"command to get and boot from syslinux files",
|
||||
"[-p] <interface> <dev[:part]> <ext2|fat|any> [addr] [filename]\n"
|
||||
" - load and parse syslinux menu file 'filename' from ext2, fat\n"
|
||||
" or any filesystem on 'dev' on 'interface' to address 'addr'"
|
||||
);
|
40
doc/README.asn1
Normal file
40
doc/README.asn1
Normal file
|
@ -0,0 +1,40 @@
|
|||
ASN1
|
||||
====
|
||||
|
||||
Abstract Syntax Notation One (or ASN1) is a standard by ITU-T and ISO/IEC
|
||||
and used as a description language for defining data structure in
|
||||
an independent manner.
|
||||
Any data described in ASN1 notation can be serialized (or encoded) and
|
||||
de-serialized (or decoded) with well-defined encoding rules.
|
||||
|
||||
A combination of ASN1 compiler and ASN1 decoder library function will
|
||||
provide a function interface for parsing encoded binary into specific
|
||||
data structure:
|
||||
1) define data structure in a text file (*.asn1)
|
||||
2) define "action" routines for specific "tags" defined in (1)
|
||||
3) generate bytecode as a C file (*.asn1.[ch]) from *.asn1 file
|
||||
with ASN1 compiler (tools/asn1_compiler)
|
||||
4) call a ASN1 decoder (asn1_ber_decoder()) with bytecode and data
|
||||
|
||||
Usage of ASN1 compiler
|
||||
----------------------
|
||||
asn1_compiler [-v] [-d] <grammar-file> <c-file> <hdr-file>
|
||||
|
||||
<grammar-file>: ASN1 input file
|
||||
<c-file>: generated C file
|
||||
<hdr-file>: generated include file
|
||||
|
||||
Usage of ASN1 decoder
|
||||
---------------------
|
||||
int asn1_ber_decoder(const struct asn1_decoder *decoder, void *context,
|
||||
const unsigned char *data, size_t datalen);
|
||||
|
||||
@decoder: bytecode binary
|
||||
@context: context for decoder
|
||||
@data: data to be parsed
|
||||
@datalen: size of data
|
||||
|
||||
|
||||
As of writing this, ASN1 compiler and decoder are used to implement
|
||||
X509 certificate parser, pcks7 message parser and RSA public key parser
|
||||
for UEFI secure boot.
|
|
@ -7,6 +7,7 @@ menu "Real Time Clock"
|
|||
config DM_RTC
|
||||
bool "Enable Driver Model for RTC drivers"
|
||||
depends on DM
|
||||
select LIB_DATE
|
||||
help
|
||||
Enable drver model for real-time-clock drivers. The RTC uclass
|
||||
then provides the rtc_get()/rtc_set() interface, delegating to
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
obj-$(CONFIG_$(SPL_TPL_)DM_RTC) += rtc-uclass.o
|
||||
|
||||
obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
|
||||
obj-y += date.o
|
||||
obj-y += rtc-lib.o
|
||||
obj-$(CONFIG_RTC_DAVINCI) += davinci.o
|
||||
obj-$(CONFIG_RTC_DS1302) += ds1302.o
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "ubifs.h"
|
||||
#include <u-boot/zlib.h>
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/lzo.h>
|
||||
|
||||
|
@ -70,24 +71,6 @@ struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
|
|||
|
||||
|
||||
#ifdef __UBOOT__
|
||||
/* from mm/util.c */
|
||||
|
||||
/**
|
||||
* kmemdup - duplicate region of memory
|
||||
*
|
||||
* @src: memory region to duplicate
|
||||
* @len: memory region length
|
||||
* @gfp: GFP mask to use
|
||||
*/
|
||||
void *kmemdup(const void *src, size_t len, gfp_t gfp)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = kmalloc(len, gfp);
|
||||
if (p)
|
||||
memcpy(p, src, len);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct crypto_comp {
|
||||
int compressor;
|
||||
|
|
57
include/crypto/internal/rsa.h
Normal file
57
include/crypto/internal/rsa.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* RSA internal helpers
|
||||
*
|
||||
* Copyright (c) 2015, Intel Corporation
|
||||
* Authors: Tadeusz Struk <tadeusz.struk@intel.com>
|
||||
*/
|
||||
#ifndef _RSA_HELPER_
|
||||
#define _RSA_HELPER_
|
||||
#include <linux/types.h>
|
||||
|
||||
/**
|
||||
* rsa_key - RSA key structure
|
||||
* @n : RSA modulus raw byte stream
|
||||
* @e : RSA public exponent raw byte stream
|
||||
* @d : RSA private exponent raw byte stream
|
||||
* @p : RSA prime factor p of n raw byte stream
|
||||
* @q : RSA prime factor q of n raw byte stream
|
||||
* @dp : RSA exponent d mod (p - 1) raw byte stream
|
||||
* @dq : RSA exponent d mod (q - 1) raw byte stream
|
||||
* @qinv : RSA CRT coefficient q^(-1) mod p raw byte stream
|
||||
* @n_sz : length in bytes of RSA modulus n
|
||||
* @e_sz : length in bytes of RSA public exponent
|
||||
* @d_sz : length in bytes of RSA private exponent
|
||||
* @p_sz : length in bytes of p field
|
||||
* @q_sz : length in bytes of q field
|
||||
* @dp_sz : length in bytes of dp field
|
||||
* @dq_sz : length in bytes of dq field
|
||||
* @qinv_sz : length in bytes of qinv field
|
||||
*/
|
||||
struct rsa_key {
|
||||
const u8 *n;
|
||||
const u8 *e;
|
||||
const u8 *d;
|
||||
const u8 *p;
|
||||
const u8 *q;
|
||||
const u8 *dp;
|
||||
const u8 *dq;
|
||||
const u8 *qinv;
|
||||
size_t n_sz;
|
||||
size_t e_sz;
|
||||
size_t d_sz;
|
||||
size_t p_sz;
|
||||
size_t q_sz;
|
||||
size_t dp_sz;
|
||||
size_t dq_sz;
|
||||
size_t qinv_sz;
|
||||
};
|
||||
|
||||
int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key,
|
||||
unsigned int key_len);
|
||||
|
||||
int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key,
|
||||
unsigned int key_len);
|
||||
|
||||
extern struct crypto_template rsa_pkcs1pad_tmpl;
|
||||
#endif
|
47
include/crypto/pkcs7.h
Normal file
47
include/crypto/pkcs7.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* PKCS#7 crypto data parser
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _CRYPTO_PKCS7_H
|
||||
#define _CRYPTO_PKCS7_H
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/verification.h>
|
||||
#include <crypto/public_key.h>
|
||||
#endif
|
||||
|
||||
struct key;
|
||||
struct pkcs7_message;
|
||||
|
||||
/*
|
||||
* pkcs7_parser.c
|
||||
*/
|
||||
extern struct pkcs7_message *pkcs7_parse_message(const void *data,
|
||||
size_t datalen);
|
||||
extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
|
||||
|
||||
extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
|
||||
const void **_data, size_t *_datalen,
|
||||
size_t *_headerlen);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/*
|
||||
* pkcs7_trust.c
|
||||
*/
|
||||
extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
|
||||
struct key *trust_keyring);
|
||||
|
||||
/*
|
||||
* pkcs7_verify.c
|
||||
*/
|
||||
extern int pkcs7_verify(struct pkcs7_message *pkcs7,
|
||||
enum key_being_used_for usage);
|
||||
|
||||
extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
|
||||
const void *data, size_t datalen);
|
||||
#endif
|
||||
|
||||
#endif /* _CRYPTO_PKCS7_H */
|
90
include/crypto/public_key.h
Normal file
90
include/crypto/public_key.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* Asymmetric public-key algorithm definitions
|
||||
*
|
||||
* See Documentation/crypto/asymmetric-keys.txt
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_PUBLIC_KEY_H
|
||||
#define _LINUX_PUBLIC_KEY_H
|
||||
|
||||
#ifdef __UBOOT__
|
||||
#include <linux/types.h>
|
||||
#else
|
||||
#include <linux/keyctl.h>
|
||||
#endif
|
||||
#include <linux/oid_registry.h>
|
||||
|
||||
/*
|
||||
* Cryptographic data for the public-key subtype of the asymmetric key type.
|
||||
*
|
||||
* Note that this may include private part of the key as well as the public
|
||||
* part.
|
||||
*/
|
||||
struct public_key {
|
||||
void *key;
|
||||
u32 keylen;
|
||||
enum OID algo;
|
||||
void *params;
|
||||
u32 paramlen;
|
||||
bool key_is_private;
|
||||
const char *id_type;
|
||||
const char *pkey_algo;
|
||||
};
|
||||
|
||||
extern void public_key_free(struct public_key *key);
|
||||
|
||||
/*
|
||||
* Public key cryptography signature data
|
||||
*/
|
||||
struct public_key_signature {
|
||||
struct asymmetric_key_id *auth_ids[2];
|
||||
u8 *s; /* Signature */
|
||||
u32 s_size; /* Number of bytes in signature */
|
||||
u8 *digest;
|
||||
u8 digest_size; /* Number of bytes in digest */
|
||||
const char *pkey_algo;
|
||||
const char *hash_algo;
|
||||
const char *encoding;
|
||||
};
|
||||
|
||||
extern void public_key_signature_free(struct public_key_signature *sig);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
extern struct asymmetric_key_subtype public_key_subtype;
|
||||
|
||||
struct key;
|
||||
struct key_type;
|
||||
union key_payload;
|
||||
|
||||
extern int restrict_link_by_signature(struct key *dest_keyring,
|
||||
const struct key_type *type,
|
||||
const union key_payload *payload,
|
||||
struct key *trust_keyring);
|
||||
|
||||
extern int restrict_link_by_key_or_keyring(struct key *dest_keyring,
|
||||
const struct key_type *type,
|
||||
const union key_payload *payload,
|
||||
struct key *trusted);
|
||||
|
||||
extern int restrict_link_by_key_or_keyring_chain(struct key *trust_keyring,
|
||||
const struct key_type *type,
|
||||
const union key_payload *payload,
|
||||
struct key *trusted);
|
||||
|
||||
extern int query_asymmetric_key(const struct kernel_pkey_params *,
|
||||
struct kernel_pkey_query *);
|
||||
|
||||
extern int encrypt_blob(struct kernel_pkey_params *, const void *, void *);
|
||||
extern int decrypt_blob(struct kernel_pkey_params *, const void *, void *);
|
||||
extern int create_signature(struct kernel_pkey_params *, const void *, void *);
|
||||
extern int verify_signature(const struct key *,
|
||||
const struct public_key_signature *);
|
||||
|
||||
int public_key_verify_signature(const struct public_key *pkey,
|
||||
const struct public_key_signature *sig);
|
||||
#endif /* !__UBOOT__ */
|
||||
|
||||
#endif /* _LINUX_PUBLIC_KEY_H */
|
|
@ -113,6 +113,16 @@ int env_match(unsigned char *name, int index);
|
|||
*/
|
||||
char *env_get(const char *varname);
|
||||
|
||||
/*
|
||||
* Like env_get, but prints an error if envvar isn't defined in the
|
||||
* environment. It always returns what env_get does, so it can be used in
|
||||
* place of env_get without changing error handling otherwise.
|
||||
*
|
||||
* @varname: Variable to look up
|
||||
* @return value of variable, or NULL if not found
|
||||
*/
|
||||
char *from_env(const char *envvar);
|
||||
|
||||
/**
|
||||
* env_get_f() - Look up the value of an environment variable (early)
|
||||
*
|
||||
|
|
88
include/keys/asymmetric-type.h
Normal file
88
include/keys/asymmetric-type.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* Asymmetric Public-key cryptography key type interface
|
||||
*
|
||||
* See Documentation/crypto/asymmetric-keys.txt
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _KEYS_ASYMMETRIC_TYPE_H
|
||||
#define _KEYS_ASYMMETRIC_TYPE_H
|
||||
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/key-type.h>
|
||||
#include <linux/verification.h>
|
||||
|
||||
extern struct key_type key_type_asymmetric;
|
||||
|
||||
/*
|
||||
* The key payload is four words. The asymmetric-type key uses them as
|
||||
* follows:
|
||||
*/
|
||||
enum asymmetric_payload_bits {
|
||||
asym_crypto, /* The data representing the key */
|
||||
asym_subtype, /* Pointer to an asymmetric_key_subtype struct */
|
||||
asym_key_ids, /* Pointer to an asymmetric_key_ids struct */
|
||||
asym_auth /* The key's authorisation (signature, parent key ID) */
|
||||
};
|
||||
#endif /* !__UBOOT__ */
|
||||
|
||||
/*
|
||||
* Identifiers for an asymmetric key ID. We have three ways of looking up a
|
||||
* key derived from an X.509 certificate:
|
||||
*
|
||||
* (1) Serial Number & Issuer. Non-optional. This is the only valid way to
|
||||
* map a PKCS#7 signature to an X.509 certificate.
|
||||
*
|
||||
* (2) Issuer & Subject Unique IDs. Optional. These were the original way to
|
||||
* match X.509 certificates, but have fallen into disuse in favour of (3).
|
||||
*
|
||||
* (3) Auth & Subject Key Identifiers. Optional. SKIDs are only provided on
|
||||
* CA keys that are intended to sign other keys, so don't appear in end
|
||||
* user certificates unless forced.
|
||||
*
|
||||
* We could also support an PGP key identifier, which is just a SHA1 sum of the
|
||||
* public key and certain parameters, but since we don't support PGP keys at
|
||||
* the moment, we shall ignore those.
|
||||
*
|
||||
* What we actually do is provide a place where binary identifiers can be
|
||||
* stashed and then compare against them when checking for an id match.
|
||||
*/
|
||||
struct asymmetric_key_id {
|
||||
unsigned short len;
|
||||
unsigned char data[];
|
||||
};
|
||||
|
||||
struct asymmetric_key_ids {
|
||||
void *id[2];
|
||||
};
|
||||
|
||||
extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
|
||||
const struct asymmetric_key_id *kid2);
|
||||
|
||||
extern bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
|
||||
const struct asymmetric_key_id *kid2);
|
||||
|
||||
extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
|
||||
size_t len_1,
|
||||
const void *val_2,
|
||||
size_t len_2);
|
||||
#ifndef __UBOOT__
|
||||
static inline
|
||||
const struct asymmetric_key_ids *asymmetric_key_ids(const struct key *key)
|
||||
{
|
||||
return key->payload.data[asym_key_ids];
|
||||
}
|
||||
|
||||
extern struct key *find_asymmetric_key(struct key *keyring,
|
||||
const struct asymmetric_key_id *id_0,
|
||||
const struct asymmetric_key_id *id_1,
|
||||
bool partial);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The payload is at the discretion of the subtype.
|
||||
*/
|
||||
|
||||
#endif /* _KEYS_ASYMMETRIC_TYPE_H */
|
65
include/linux/asn1.h
Normal file
65
include/linux/asn1.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* ASN.1 BER/DER/CER encoding definitions
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ASN1_H
|
||||
#define _LINUX_ASN1_H
|
||||
|
||||
/* Class */
|
||||
enum asn1_class {
|
||||
ASN1_UNIV = 0, /* Universal */
|
||||
ASN1_APPL = 1, /* Application */
|
||||
ASN1_CONT = 2, /* Context */
|
||||
ASN1_PRIV = 3 /* Private */
|
||||
};
|
||||
#define ASN1_CLASS_BITS 0xc0
|
||||
|
||||
|
||||
enum asn1_method {
|
||||
ASN1_PRIM = 0, /* Primitive */
|
||||
ASN1_CONS = 1 /* Constructed */
|
||||
};
|
||||
#define ASN1_CONS_BIT 0x20
|
||||
|
||||
/* Tag */
|
||||
enum asn1_tag {
|
||||
ASN1_EOC = 0, /* End Of Contents or N/A */
|
||||
ASN1_BOOL = 1, /* Boolean */
|
||||
ASN1_INT = 2, /* Integer */
|
||||
ASN1_BTS = 3, /* Bit String */
|
||||
ASN1_OTS = 4, /* Octet String */
|
||||
ASN1_NULL = 5, /* Null */
|
||||
ASN1_OID = 6, /* Object Identifier */
|
||||
ASN1_ODE = 7, /* Object Description */
|
||||
ASN1_EXT = 8, /* External */
|
||||
ASN1_REAL = 9, /* Real float */
|
||||
ASN1_ENUM = 10, /* Enumerated */
|
||||
ASN1_EPDV = 11, /* Embedded PDV */
|
||||
ASN1_UTF8STR = 12, /* UTF8 String */
|
||||
ASN1_RELOID = 13, /* Relative OID */
|
||||
/* 14 - Reserved */
|
||||
/* 15 - Reserved */
|
||||
ASN1_SEQ = 16, /* Sequence and Sequence of */
|
||||
ASN1_SET = 17, /* Set and Set of */
|
||||
ASN1_NUMSTR = 18, /* Numerical String */
|
||||
ASN1_PRNSTR = 19, /* Printable String */
|
||||
ASN1_TEXSTR = 20, /* T61 String / Teletext String */
|
||||
ASN1_VIDSTR = 21, /* Videotex String */
|
||||
ASN1_IA5STR = 22, /* IA5 String */
|
||||
ASN1_UNITIM = 23, /* Universal Time */
|
||||
ASN1_GENTIM = 24, /* General Time */
|
||||
ASN1_GRASTR = 25, /* Graphic String */
|
||||
ASN1_VISSTR = 26, /* Visible String */
|
||||
ASN1_GENSTR = 27, /* General String */
|
||||
ASN1_UNISTR = 28, /* Universal String */
|
||||
ASN1_CHRSTR = 29, /* Character String */
|
||||
ASN1_BMPSTR = 30, /* BMP String */
|
||||
ASN1_LONG_TAG = 31 /* Long form tag */
|
||||
};
|
||||
|
||||
#define ASN1_INDEFINITE_LENGTH 0x80
|
||||
|
||||
#endif /* _LINUX_ASN1_H */
|
89
include/linux/asn1_ber_bytecode.h
Normal file
89
include/linux/asn1_ber_bytecode.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* ASN.1 BER/DER/CER parsing state machine internal definitions
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ASN1_BER_BYTECODE_H
|
||||
#define _LINUX_ASN1_BER_BYTECODE_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
#include <linux/asn1.h>
|
||||
|
||||
typedef int (*asn1_action_t)(void *context,
|
||||
size_t hdrlen, /* In case of ANY type */
|
||||
unsigned char tag, /* In case of ANY type */
|
||||
const void *value, size_t vlen);
|
||||
|
||||
struct asn1_decoder {
|
||||
const unsigned char *machine;
|
||||
size_t machlen;
|
||||
const asn1_action_t *actions;
|
||||
};
|
||||
|
||||
enum asn1_opcode {
|
||||
/* The tag-matching ops come first and the odd-numbered slots
|
||||
* are for OR_SKIP ops.
|
||||
*/
|
||||
#define ASN1_OP_MATCH__SKIP 0x01
|
||||
#define ASN1_OP_MATCH__ACT 0x02
|
||||
#define ASN1_OP_MATCH__JUMP 0x04
|
||||
#define ASN1_OP_MATCH__ANY 0x08
|
||||
#define ASN1_OP_MATCH__COND 0x10
|
||||
|
||||
ASN1_OP_MATCH = 0x00,
|
||||
ASN1_OP_MATCH_OR_SKIP = 0x01,
|
||||
ASN1_OP_MATCH_ACT = 0x02,
|
||||
ASN1_OP_MATCH_ACT_OR_SKIP = 0x03,
|
||||
ASN1_OP_MATCH_JUMP = 0x04,
|
||||
ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05,
|
||||
ASN1_OP_MATCH_ANY = 0x08,
|
||||
ASN1_OP_MATCH_ANY_OR_SKIP = 0x09,
|
||||
ASN1_OP_MATCH_ANY_ACT = 0x0a,
|
||||
ASN1_OP_MATCH_ANY_ACT_OR_SKIP = 0x0b,
|
||||
/* Everything before here matches unconditionally */
|
||||
|
||||
ASN1_OP_COND_MATCH_OR_SKIP = 0x11,
|
||||
ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13,
|
||||
ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15,
|
||||
ASN1_OP_COND_MATCH_ANY = 0x18,
|
||||
ASN1_OP_COND_MATCH_ANY_OR_SKIP = 0x19,
|
||||
ASN1_OP_COND_MATCH_ANY_ACT = 0x1a,
|
||||
ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP = 0x1b,
|
||||
|
||||
/* Everything before here will want a tag from the data */
|
||||
#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP
|
||||
|
||||
/* These are here to help fill up space */
|
||||
ASN1_OP_COND_FAIL = 0x1c,
|
||||
ASN1_OP_COMPLETE = 0x1d,
|
||||
ASN1_OP_ACT = 0x1e,
|
||||
ASN1_OP_MAYBE_ACT = 0x1f,
|
||||
|
||||
/* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */
|
||||
ASN1_OP_END_SEQ = 0x20,
|
||||
ASN1_OP_END_SET = 0x21,
|
||||
ASN1_OP_END_SEQ_OF = 0x22,
|
||||
ASN1_OP_END_SET_OF = 0x23,
|
||||
ASN1_OP_END_SEQ_ACT = 0x24,
|
||||
ASN1_OP_END_SET_ACT = 0x25,
|
||||
ASN1_OP_END_SEQ_OF_ACT = 0x26,
|
||||
ASN1_OP_END_SET_OF_ACT = 0x27,
|
||||
#define ASN1_OP_END__SET 0x01
|
||||
#define ASN1_OP_END__OF 0x02
|
||||
#define ASN1_OP_END__ACT 0x04
|
||||
|
||||
ASN1_OP_RETURN = 0x28,
|
||||
|
||||
ASN1_OP__NR
|
||||
};
|
||||
|
||||
#define _tag(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | ASN1_##TAG)
|
||||
#define _tagn(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | TAG)
|
||||
#define _jump_target(N) (N)
|
||||
#define _action(N) (N)
|
||||
|
||||
#endif /* _LINUX_ASN1_BER_BYTECODE_H */
|
20
include/linux/asn1_decoder.h
Normal file
20
include/linux/asn1_decoder.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* ASN.1 decoder
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ASN1_DECODER_H
|
||||
#define _LINUX_ASN1_DECODER_H
|
||||
|
||||
#include <linux/asn1.h>
|
||||
|
||||
struct asn1_decoder;
|
||||
|
||||
extern int asn1_ber_decoder(const struct asn1_decoder *decoder,
|
||||
void *context,
|
||||
const unsigned char *data,
|
||||
size_t datalen);
|
||||
|
||||
#endif /* _LINUX_ASN1_DECODER_H */
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef _LINUX_KERNEL_H
|
||||
#define _LINUX_KERNEL_H
|
||||
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/printk.h> /* for printf/pr_* utilities */
|
||||
|
||||
#define USHRT_MAX ((u16)(~0U))
|
||||
#define SHRT_MAX ((s16)(USHRT_MAX>>1))
|
||||
|
|
117
include/linux/oid_registry.h
Normal file
117
include/linux/oid_registry.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/* 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)
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_OID_REGISTRY_H
|
||||
#define _LINUX_OID_REGISTRY_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* OIDs are turned into these values if possible, or OID__NR if not held here.
|
||||
*
|
||||
* NOTE! Do not mess with the format of each line as this is read by
|
||||
* build_OID_registry.pl to generate the data for look_up_OID().
|
||||
*/
|
||||
enum OID {
|
||||
OID_id_dsa_with_sha1, /* 1.2.840.10030.4.3 */
|
||||
OID_id_dsa, /* 1.2.840.10040.4.1 */
|
||||
OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */
|
||||
OID_id_ecPublicKey, /* 1.2.840.10045.2.1 */
|
||||
|
||||
/* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */
|
||||
OID_rsaEncryption, /* 1.2.840.113549.1.1.1 */
|
||||
OID_md2WithRSAEncryption, /* 1.2.840.113549.1.1.2 */
|
||||
OID_md3WithRSAEncryption, /* 1.2.840.113549.1.1.3 */
|
||||
OID_md4WithRSAEncryption, /* 1.2.840.113549.1.1.4 */
|
||||
OID_sha1WithRSAEncryption, /* 1.2.840.113549.1.1.5 */
|
||||
OID_sha256WithRSAEncryption, /* 1.2.840.113549.1.1.11 */
|
||||
OID_sha384WithRSAEncryption, /* 1.2.840.113549.1.1.12 */
|
||||
OID_sha512WithRSAEncryption, /* 1.2.840.113549.1.1.13 */
|
||||
OID_sha224WithRSAEncryption, /* 1.2.840.113549.1.1.14 */
|
||||
/* PKCS#7 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7)} */
|
||||
OID_data, /* 1.2.840.113549.1.7.1 */
|
||||
OID_signed_data, /* 1.2.840.113549.1.7.2 */
|
||||
/* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */
|
||||
OID_email_address, /* 1.2.840.113549.1.9.1 */
|
||||
OID_contentType, /* 1.2.840.113549.1.9.3 */
|
||||
OID_messageDigest, /* 1.2.840.113549.1.9.4 */
|
||||
OID_signingTime, /* 1.2.840.113549.1.9.5 */
|
||||
OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */
|
||||
OID_smimeAuthenticatedAttrs, /* 1.2.840.113549.1.9.16.2.11 */
|
||||
|
||||
/* {iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2)} */
|
||||
OID_md2, /* 1.2.840.113549.2.2 */
|
||||
OID_md4, /* 1.2.840.113549.2.4 */
|
||||
OID_md5, /* 1.2.840.113549.2.5 */
|
||||
|
||||
/* Microsoft Authenticode & Software Publishing */
|
||||
OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */
|
||||
OID_msStatementType, /* 1.3.6.1.4.1.311.2.1.11 */
|
||||
OID_msSpOpusInfo, /* 1.3.6.1.4.1.311.2.1.12 */
|
||||
OID_msPeImageDataObjId, /* 1.3.6.1.4.1.311.2.1.15 */
|
||||
OID_msIndividualSPKeyPurpose, /* 1.3.6.1.4.1.311.2.1.21 */
|
||||
OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
|
||||
|
||||
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
|
||||
OID_sha1, /* 1.3.14.3.2.26 */
|
||||
OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
|
||||
OID_sha384, /* 2.16.840.1.101.3.4.2.2 */
|
||||
OID_sha512, /* 2.16.840.1.101.3.4.2.3 */
|
||||
OID_sha224, /* 2.16.840.1.101.3.4.2.4 */
|
||||
|
||||
/* Distinguished Name attribute IDs [RFC 2256] */
|
||||
OID_commonName, /* 2.5.4.3 */
|
||||
OID_surname, /* 2.5.4.4 */
|
||||
OID_countryName, /* 2.5.4.6 */
|
||||
OID_locality, /* 2.5.4.7 */
|
||||
OID_stateOrProvinceName, /* 2.5.4.8 */
|
||||
OID_organizationName, /* 2.5.4.10 */
|
||||
OID_organizationUnitName, /* 2.5.4.11 */
|
||||
OID_title, /* 2.5.4.12 */
|
||||
OID_description, /* 2.5.4.13 */
|
||||
OID_name, /* 2.5.4.41 */
|
||||
OID_givenName, /* 2.5.4.42 */
|
||||
OID_initials, /* 2.5.4.43 */
|
||||
OID_generationalQualifier, /* 2.5.4.44 */
|
||||
|
||||
/* Certificate extension IDs */
|
||||
OID_subjectKeyIdentifier, /* 2.5.29.14 */
|
||||
OID_keyUsage, /* 2.5.29.15 */
|
||||
OID_subjectAltName, /* 2.5.29.17 */
|
||||
OID_issuerAltName, /* 2.5.29.18 */
|
||||
OID_basicConstraints, /* 2.5.29.19 */
|
||||
OID_crlDistributionPoints, /* 2.5.29.31 */
|
||||
OID_certPolicies, /* 2.5.29.32 */
|
||||
OID_authorityKeyIdentifier, /* 2.5.29.35 */
|
||||
OID_extKeyUsage, /* 2.5.29.37 */
|
||||
|
||||
/* EC-RDSA */
|
||||
OID_gostCPSignA, /* 1.2.643.2.2.35.1 */
|
||||
OID_gostCPSignB, /* 1.2.643.2.2.35.2 */
|
||||
OID_gostCPSignC, /* 1.2.643.2.2.35.3 */
|
||||
OID_gost2012PKey256, /* 1.2.643.7.1.1.1.1 */
|
||||
OID_gost2012PKey512, /* 1.2.643.7.1.1.1.2 */
|
||||
OID_gost2012Digest256, /* 1.2.643.7.1.1.2.2 */
|
||||
OID_gost2012Digest512, /* 1.2.643.7.1.1.2.3 */
|
||||
OID_gost2012Signature256, /* 1.2.643.7.1.1.3.2 */
|
||||
OID_gost2012Signature512, /* 1.2.643.7.1.1.3.3 */
|
||||
OID_gostTC26Sign256A, /* 1.2.643.7.1.2.1.1.1 */
|
||||
OID_gostTC26Sign256B, /* 1.2.643.7.1.2.1.1.2 */
|
||||
OID_gostTC26Sign256C, /* 1.2.643.7.1.2.1.1.3 */
|
||||
OID_gostTC26Sign256D, /* 1.2.643.7.1.2.1.1.4 */
|
||||
OID_gostTC26Sign512A, /* 1.2.643.7.1.2.1.2.1 */
|
||||
OID_gostTC26Sign512B, /* 1.2.643.7.1.2.1.2.2 */
|
||||
OID_gostTC26Sign512C, /* 1.2.643.7.1.2.1.2.3 */
|
||||
|
||||
OID__NR
|
||||
};
|
||||
|
||||
extern enum OID look_up_OID(const void *data, size_t datasize);
|
||||
extern int sprint_oid(const void *, size_t, char *, size_t);
|
||||
extern int sprint_OID(enum OID, char *, size_t);
|
||||
|
||||
#endif /* _LINUX_OID_REGISTRY_H */
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef _LINUX_TIME_H
|
||||
#define _LINUX_TIME_H
|
||||
|
||||
#include <rtc.h>
|
||||
#include <vsprintf.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define _DEFUN(a,b,c) a(c)
|
||||
|
@ -150,4 +152,13 @@ _DEFUN (ctime_r, (tim_p, result),
|
|||
return asctime_r (localtime_r (tim_p, &tm), result);
|
||||
}
|
||||
|
||||
/* for compatibility with linux code */
|
||||
typedef __s64 time64_t;
|
||||
|
||||
#ifdef CONFIG_LIB_DATE
|
||||
time64_t mktime64(const unsigned int year, const unsigned int mon,
|
||||
const unsigned int day, const unsigned int hour,
|
||||
const unsigned int min, const unsigned int sec);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
#ifdef CONFIG_DM_RTC
|
||||
|
||||
struct udevice;
|
||||
|
||||
struct rtc_ops {
|
||||
/**
|
||||
* get() - get the current time
|
||||
|
|
17
lib/Kconfig
17
lib/Kconfig
|
@ -265,6 +265,7 @@ config AES
|
|||
present.
|
||||
|
||||
source lib/rsa/Kconfig
|
||||
source lib/crypto/Kconfig
|
||||
|
||||
config TPM
|
||||
bool "Trusted Platform Module (TPM) Support"
|
||||
|
@ -566,6 +567,19 @@ config SMBIOS_PRODUCT_NAME
|
|||
|
||||
endmenu
|
||||
|
||||
config ASN1_COMPILER
|
||||
bool
|
||||
|
||||
config ASN1_DECODER
|
||||
bool
|
||||
help
|
||||
Enable asn1 decoder library.
|
||||
|
||||
config OID_REGISTRY
|
||||
bool
|
||||
help
|
||||
Enable fast lookup object identifier registry.
|
||||
|
||||
source lib/efi/Kconfig
|
||||
source lib/efi_loader/Kconfig
|
||||
source lib/optee/Kconfig
|
||||
|
@ -574,4 +588,7 @@ config TEST_FDTDEC
|
|||
bool "enable fdtdec test"
|
||||
depends on OF_LIBFDT
|
||||
|
||||
config LIB_DATE
|
||||
bool
|
||||
|
||||
endmenu
|
||||
|
|
20
lib/Makefile
20
lib/Makefile
|
@ -17,6 +17,8 @@ obj-$(CONFIG_OF_LIVE) += of_live.o
|
|||
obj-$(CONFIG_CMD_DHRYSTONE) += dhry/
|
||||
obj-$(CONFIG_ARCH_AT91) += at91/
|
||||
obj-$(CONFIG_OPTEE) += optee/
|
||||
obj-$(CONFIG_ASN1_DECODER) += asn1_decoder.o
|
||||
obj-y += crypto/
|
||||
|
||||
obj-$(CONFIG_AES) += aes.o
|
||||
|
||||
|
@ -117,4 +119,22 @@ else
|
|||
obj-y += vsprintf.o strto.o
|
||||
endif
|
||||
|
||||
obj-y += date.o
|
||||
|
||||
#
|
||||
# Build a fast OID lookup registry from include/linux/oid_registry.h
|
||||
#
|
||||
obj-$(CONFIG_OID_REGISTRY) += oid_registry.o
|
||||
|
||||
$(obj)/oid_registry.o: $(obj)/oid_registry_data.c
|
||||
|
||||
$(obj)/oid_registry_data.c: $(srctree)/include/linux/oid_registry.h \
|
||||
$(srctree)/scripts/build_OID_registry
|
||||
$(call cmd,build_OID_registry)
|
||||
|
||||
quiet_cmd_build_OID_registry = GEN $@
|
||||
cmd_build_OID_registry = perl $(srctree)/scripts/build_OID_registry $< $@
|
||||
|
||||
clean-files += oid_registry_data.c
|
||||
|
||||
subdir-ccflags-$(CONFIG_CC_OPTIMIZE_LIBS_FOR_SPEED) += -O2
|
||||
|
|
527
lib/asn1_decoder.c
Normal file
527
lib/asn1_decoder.c
Normal file
|
@ -0,0 +1,527 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Decoder for ASN.1 BER/DER/CER encoded bytestream
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#ifdef __UBOOT__
|
||||
#include <linux/compat.h>
|
||||
#else
|
||||
#include <linux/export.h>
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/module.h>
|
||||
#endif
|
||||
#include <linux/asn1_decoder.h>
|
||||
#include <linux/asn1_ber_bytecode.h>
|
||||
|
||||
static const unsigned char asn1_op_lengths[ASN1_OP__NR] = {
|
||||
/* OPC TAG JMP ACT */
|
||||
[ASN1_OP_MATCH] = 1 + 1,
|
||||
[ASN1_OP_MATCH_OR_SKIP] = 1 + 1,
|
||||
[ASN1_OP_MATCH_ACT] = 1 + 1 + 1,
|
||||
[ASN1_OP_MATCH_ACT_OR_SKIP] = 1 + 1 + 1,
|
||||
[ASN1_OP_MATCH_JUMP] = 1 + 1 + 1,
|
||||
[ASN1_OP_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
|
||||
[ASN1_OP_MATCH_ANY] = 1,
|
||||
[ASN1_OP_MATCH_ANY_OR_SKIP] = 1,
|
||||
[ASN1_OP_MATCH_ANY_ACT] = 1 + 1,
|
||||
[ASN1_OP_MATCH_ANY_ACT_OR_SKIP] = 1 + 1,
|
||||
[ASN1_OP_COND_MATCH_OR_SKIP] = 1 + 1,
|
||||
[ASN1_OP_COND_MATCH_ACT_OR_SKIP] = 1 + 1 + 1,
|
||||
[ASN1_OP_COND_MATCH_JUMP_OR_SKIP] = 1 + 1 + 1,
|
||||
[ASN1_OP_COND_MATCH_ANY] = 1,
|
||||
[ASN1_OP_COND_MATCH_ANY_OR_SKIP] = 1,
|
||||
[ASN1_OP_COND_MATCH_ANY_ACT] = 1 + 1,
|
||||
[ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP] = 1 + 1,
|
||||
[ASN1_OP_COND_FAIL] = 1,
|
||||
[ASN1_OP_COMPLETE] = 1,
|
||||
[ASN1_OP_ACT] = 1 + 1,
|
||||
[ASN1_OP_MAYBE_ACT] = 1 + 1,
|
||||
[ASN1_OP_RETURN] = 1,
|
||||
[ASN1_OP_END_SEQ] = 1,
|
||||
[ASN1_OP_END_SEQ_OF] = 1 + 1,
|
||||
[ASN1_OP_END_SET] = 1,
|
||||
[ASN1_OP_END_SET_OF] = 1 + 1,
|
||||
[ASN1_OP_END_SEQ_ACT] = 1 + 1,
|
||||
[ASN1_OP_END_SEQ_OF_ACT] = 1 + 1 + 1,
|
||||
[ASN1_OP_END_SET_ACT] = 1 + 1,
|
||||
[ASN1_OP_END_SET_OF_ACT] = 1 + 1 + 1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Find the length of an indefinite length object
|
||||
* @data: The data buffer
|
||||
* @datalen: The end of the innermost containing element in the buffer
|
||||
* @_dp: The data parse cursor (updated before returning)
|
||||
* @_len: Where to return the size of the element.
|
||||
* @_errmsg: Where to return a pointer to an error message on error
|
||||
*/
|
||||
static int asn1_find_indefinite_length(const unsigned char *data, size_t datalen,
|
||||
size_t *_dp, size_t *_len,
|
||||
const char **_errmsg)
|
||||
{
|
||||
unsigned char tag, tmp;
|
||||
size_t dp = *_dp, len, n;
|
||||
int indef_level = 1;
|
||||
|
||||
next_tag:
|
||||
if (unlikely(datalen - dp < 2)) {
|
||||
if (datalen == dp)
|
||||
goto missing_eoc;
|
||||
goto data_overrun_error;
|
||||
}
|
||||
|
||||
/* Extract a tag from the data */
|
||||
tag = data[dp++];
|
||||
if (tag == ASN1_EOC) {
|
||||
/* It appears to be an EOC. */
|
||||
if (data[dp++] != 0)
|
||||
goto invalid_eoc;
|
||||
if (--indef_level <= 0) {
|
||||
*_len = dp - *_dp;
|
||||
*_dp = dp;
|
||||
return 0;
|
||||
}
|
||||
goto next_tag;
|
||||
}
|
||||
|
||||
if (unlikely((tag & 0x1f) == ASN1_LONG_TAG)) {
|
||||
do {
|
||||
if (unlikely(datalen - dp < 2))
|
||||
goto data_overrun_error;
|
||||
tmp = data[dp++];
|
||||
} while (tmp & 0x80);
|
||||
}
|
||||
|
||||
/* Extract the length */
|
||||
len = data[dp++];
|
||||
if (len <= 0x7f)
|
||||
goto check_length;
|
||||
|
||||
if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
|
||||
/* Indefinite length */
|
||||
if (unlikely((tag & ASN1_CONS_BIT) == ASN1_PRIM << 5))
|
||||
goto indefinite_len_primitive;
|
||||
indef_level++;
|
||||
goto next_tag;
|
||||
}
|
||||
|
||||
n = len - 0x80;
|
||||
if (unlikely(n > sizeof(len) - 1))
|
||||
goto length_too_long;
|
||||
if (unlikely(n > datalen - dp))
|
||||
goto data_overrun_error;
|
||||
len = 0;
|
||||
for (; n > 0; n--) {
|
||||
len <<= 8;
|
||||
len |= data[dp++];
|
||||
}
|
||||
check_length:
|
||||
if (len > datalen - dp)
|
||||
goto data_overrun_error;
|
||||
dp += len;
|
||||
goto next_tag;
|
||||
|
||||
length_too_long:
|
||||
*_errmsg = "Unsupported length";
|
||||
goto error;
|
||||
indefinite_len_primitive:
|
||||
*_errmsg = "Indefinite len primitive not permitted";
|
||||
goto error;
|
||||
invalid_eoc:
|
||||
*_errmsg = "Invalid length EOC";
|
||||
goto error;
|
||||
data_overrun_error:
|
||||
*_errmsg = "Data overrun error";
|
||||
goto error;
|
||||
missing_eoc:
|
||||
*_errmsg = "Missing EOC in indefinite len cons";
|
||||
error:
|
||||
*_dp = dp;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* asn1_ber_decoder - Decoder BER/DER/CER ASN.1 according to pattern
|
||||
* @decoder: The decoder definition (produced by asn1_compiler)
|
||||
* @context: The caller's context (to be passed to the action functions)
|
||||
* @data: The encoded data
|
||||
* @datalen: The size of the encoded data
|
||||
*
|
||||
* Decode BER/DER/CER encoded ASN.1 data according to a bytecode pattern
|
||||
* produced by asn1_compiler. Action functions are called on marked tags to
|
||||
* allow the caller to retrieve significant data.
|
||||
*
|
||||
* LIMITATIONS:
|
||||
*
|
||||
* To keep down the amount of stack used by this function, the following limits
|
||||
* have been imposed:
|
||||
*
|
||||
* (1) This won't handle datalen > 65535 without increasing the size of the
|
||||
* cons stack elements and length_too_long checking.
|
||||
*
|
||||
* (2) The stack of constructed types is 10 deep. If the depth of non-leaf
|
||||
* constructed types exceeds this, the decode will fail.
|
||||
*
|
||||
* (3) The SET type (not the SET OF type) isn't really supported as tracking
|
||||
* what members of the set have been seen is a pain.
|
||||
*/
|
||||
int asn1_ber_decoder(const struct asn1_decoder *decoder,
|
||||
void *context,
|
||||
const unsigned char *data,
|
||||
size_t datalen)
|
||||
{
|
||||
const unsigned char *machine = decoder->machine;
|
||||
const asn1_action_t *actions = decoder->actions;
|
||||
size_t machlen = decoder->machlen;
|
||||
enum asn1_opcode op;
|
||||
unsigned char tag = 0, csp = 0, jsp = 0, optag = 0, hdr = 0;
|
||||
const char *errmsg;
|
||||
size_t pc = 0, dp = 0, tdp = 0, len = 0;
|
||||
int ret;
|
||||
|
||||
unsigned char flags = 0;
|
||||
#define FLAG_INDEFINITE_LENGTH 0x01
|
||||
#define FLAG_MATCHED 0x02
|
||||
#define FLAG_LAST_MATCHED 0x04 /* Last tag matched */
|
||||
#define FLAG_CONS 0x20 /* Corresponds to CONS bit in the opcode tag
|
||||
* - ie. whether or not we are going to parse
|
||||
* a compound type.
|
||||
*/
|
||||
|
||||
#define NR_CONS_STACK 10
|
||||
unsigned short cons_dp_stack[NR_CONS_STACK];
|
||||
unsigned short cons_datalen_stack[NR_CONS_STACK];
|
||||
unsigned char cons_hdrlen_stack[NR_CONS_STACK];
|
||||
#define NR_JUMP_STACK 10
|
||||
unsigned char jump_stack[NR_JUMP_STACK];
|
||||
|
||||
if (datalen > 65535)
|
||||
return -EMSGSIZE;
|
||||
|
||||
next_op:
|
||||
pr_debug("next_op: pc=\e[32m%zu\e[m/%zu dp=\e[33m%zu\e[m/%zu C=%d J=%d\n",
|
||||
pc, machlen, dp, datalen, csp, jsp);
|
||||
if (unlikely(pc >= machlen))
|
||||
goto machine_overrun_error;
|
||||
op = machine[pc];
|
||||
if (unlikely(pc + asn1_op_lengths[op] > machlen))
|
||||
goto machine_overrun_error;
|
||||
|
||||
/* If this command is meant to match a tag, then do that before
|
||||
* evaluating the command.
|
||||
*/
|
||||
if (op <= ASN1_OP__MATCHES_TAG) {
|
||||
unsigned char tmp;
|
||||
|
||||
/* Skip conditional matches if possible */
|
||||
if ((op & ASN1_OP_MATCH__COND && flags & FLAG_MATCHED) ||
|
||||
(op & ASN1_OP_MATCH__SKIP && dp == datalen)) {
|
||||
flags &= ~FLAG_LAST_MATCHED;
|
||||
pc += asn1_op_lengths[op];
|
||||
goto next_op;
|
||||
}
|
||||
|
||||
flags = 0;
|
||||
hdr = 2;
|
||||
|
||||
/* Extract a tag from the data */
|
||||
if (unlikely(datalen - dp < 2))
|
||||
goto data_overrun_error;
|
||||
tag = data[dp++];
|
||||
if (unlikely((tag & 0x1f) == ASN1_LONG_TAG))
|
||||
goto long_tag_not_supported;
|
||||
|
||||
if (op & ASN1_OP_MATCH__ANY) {
|
||||
pr_debug("- any %02x\n", tag);
|
||||
} else {
|
||||
/* Extract the tag from the machine
|
||||
* - Either CONS or PRIM are permitted in the data if
|
||||
* CONS is not set in the op stream, otherwise CONS
|
||||
* is mandatory.
|
||||
*/
|
||||
optag = machine[pc + 1];
|
||||
flags |= optag & FLAG_CONS;
|
||||
|
||||
/* Determine whether the tag matched */
|
||||
tmp = optag ^ tag;
|
||||
tmp &= ~(optag & ASN1_CONS_BIT);
|
||||
pr_debug("- match? %02x %02x %02x\n", tag, optag, tmp);
|
||||
if (tmp != 0) {
|
||||
/* All odd-numbered tags are MATCH_OR_SKIP. */
|
||||
if (op & ASN1_OP_MATCH__SKIP) {
|
||||
pc += asn1_op_lengths[op];
|
||||
dp--;
|
||||
goto next_op;
|
||||
}
|
||||
goto tag_mismatch;
|
||||
}
|
||||
}
|
||||
flags |= FLAG_MATCHED;
|
||||
|
||||
len = data[dp++];
|
||||
if (len > 0x7f) {
|
||||
if (unlikely(len == ASN1_INDEFINITE_LENGTH)) {
|
||||
/* Indefinite length */
|
||||
if (unlikely(!(tag & ASN1_CONS_BIT)))
|
||||
goto indefinite_len_primitive;
|
||||
flags |= FLAG_INDEFINITE_LENGTH;
|
||||
if (unlikely(2 > datalen - dp))
|
||||
goto data_overrun_error;
|
||||
} else {
|
||||
int n = len - 0x80;
|
||||
if (unlikely(n > 2))
|
||||
goto length_too_long;
|
||||
if (unlikely(n > datalen - dp))
|
||||
goto data_overrun_error;
|
||||
hdr += n;
|
||||
for (len = 0; n > 0; n--) {
|
||||
len <<= 8;
|
||||
len |= data[dp++];
|
||||
}
|
||||
if (unlikely(len > datalen - dp))
|
||||
goto data_overrun_error;
|
||||
}
|
||||
} else {
|
||||
if (unlikely(len > datalen - dp))
|
||||
goto data_overrun_error;
|
||||
}
|
||||
|
||||
if (flags & FLAG_CONS) {
|
||||
/* For expected compound forms, we stack the positions
|
||||
* of the start and end of the data.
|
||||
*/
|
||||
if (unlikely(csp >= NR_CONS_STACK))
|
||||
goto cons_stack_overflow;
|
||||
cons_dp_stack[csp] = dp;
|
||||
cons_hdrlen_stack[csp] = hdr;
|
||||
if (!(flags & FLAG_INDEFINITE_LENGTH)) {
|
||||
cons_datalen_stack[csp] = datalen;
|
||||
datalen = dp + len;
|
||||
} else {
|
||||
cons_datalen_stack[csp] = 0;
|
||||
}
|
||||
csp++;
|
||||
}
|
||||
|
||||
pr_debug("- TAG: %02x %zu%s\n",
|
||||
tag, len, flags & FLAG_CONS ? " CONS" : "");
|
||||
tdp = dp;
|
||||
}
|
||||
|
||||
/* Decide how to handle the operation */
|
||||
switch (op) {
|
||||
case ASN1_OP_MATCH:
|
||||
case ASN1_OP_MATCH_OR_SKIP:
|
||||
case ASN1_OP_MATCH_ACT:
|
||||
case ASN1_OP_MATCH_ACT_OR_SKIP:
|
||||
case ASN1_OP_MATCH_ANY:
|
||||
case ASN1_OP_MATCH_ANY_OR_SKIP:
|
||||
case ASN1_OP_MATCH_ANY_ACT:
|
||||
case ASN1_OP_MATCH_ANY_ACT_OR_SKIP:
|
||||
case ASN1_OP_COND_MATCH_OR_SKIP:
|
||||
case ASN1_OP_COND_MATCH_ACT_OR_SKIP:
|
||||
case ASN1_OP_COND_MATCH_ANY:
|
||||
case ASN1_OP_COND_MATCH_ANY_OR_SKIP:
|
||||
case ASN1_OP_COND_MATCH_ANY_ACT:
|
||||
case ASN1_OP_COND_MATCH_ANY_ACT_OR_SKIP:
|
||||
|
||||
if (!(flags & FLAG_CONS)) {
|
||||
if (flags & FLAG_INDEFINITE_LENGTH) {
|
||||
size_t tmp = dp;
|
||||
|
||||
ret = asn1_find_indefinite_length(
|
||||
data, datalen, &tmp, &len, &errmsg);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
}
|
||||
pr_debug("- LEAF: %zu\n", len);
|
||||
}
|
||||
|
||||
if (op & ASN1_OP_MATCH__ACT) {
|
||||
unsigned char act;
|
||||
|
||||
if (op & ASN1_OP_MATCH__ANY)
|
||||
act = machine[pc + 1];
|
||||
else
|
||||
act = machine[pc + 2];
|
||||
ret = actions[act](context, hdr, tag, data + dp, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(flags & FLAG_CONS))
|
||||
dp += len;
|
||||
pc += asn1_op_lengths[op];
|
||||
goto next_op;
|
||||
|
||||
case ASN1_OP_MATCH_JUMP:
|
||||
case ASN1_OP_MATCH_JUMP_OR_SKIP:
|
||||
case ASN1_OP_COND_MATCH_JUMP_OR_SKIP:
|
||||
pr_debug("- MATCH_JUMP\n");
|
||||
if (unlikely(jsp == NR_JUMP_STACK))
|
||||
goto jump_stack_overflow;
|
||||
jump_stack[jsp++] = pc + asn1_op_lengths[op];
|
||||
pc = machine[pc + 2];
|
||||
goto next_op;
|
||||
|
||||
case ASN1_OP_COND_FAIL:
|
||||
if (unlikely(!(flags & FLAG_MATCHED)))
|
||||
goto tag_mismatch;
|
||||
pc += asn1_op_lengths[op];
|
||||
goto next_op;
|
||||
|
||||
case ASN1_OP_COMPLETE:
|
||||
if (unlikely(jsp != 0 || csp != 0)) {
|
||||
pr_err("ASN.1 decoder error: Stacks not empty at completion (%u, %u)\n",
|
||||
jsp, csp);
|
||||
return -EBADMSG;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case ASN1_OP_END_SET:
|
||||
case ASN1_OP_END_SET_ACT:
|
||||
if (unlikely(!(flags & FLAG_MATCHED)))
|
||||
goto tag_mismatch;
|
||||
/* fall through */
|
||||
|
||||
case ASN1_OP_END_SEQ:
|
||||
case ASN1_OP_END_SET_OF:
|
||||
case ASN1_OP_END_SEQ_OF:
|
||||
case ASN1_OP_END_SEQ_ACT:
|
||||
case ASN1_OP_END_SET_OF_ACT:
|
||||
case ASN1_OP_END_SEQ_OF_ACT:
|
||||
if (unlikely(csp <= 0))
|
||||
goto cons_stack_underflow;
|
||||
csp--;
|
||||
tdp = cons_dp_stack[csp];
|
||||
hdr = cons_hdrlen_stack[csp];
|
||||
len = datalen;
|
||||
datalen = cons_datalen_stack[csp];
|
||||
pr_debug("- end cons t=%zu dp=%zu l=%zu/%zu\n",
|
||||
tdp, dp, len, datalen);
|
||||
if (datalen == 0) {
|
||||
/* Indefinite length - check for the EOC. */
|
||||
datalen = len;
|
||||
if (unlikely(datalen - dp < 2))
|
||||
goto data_overrun_error;
|
||||
if (data[dp++] != 0) {
|
||||
if (op & ASN1_OP_END__OF) {
|
||||
dp--;
|
||||
csp++;
|
||||
pc = machine[pc + 1];
|
||||
pr_debug("- continue\n");
|
||||
goto next_op;
|
||||
}
|
||||
goto missing_eoc;
|
||||
}
|
||||
if (data[dp++] != 0)
|
||||
goto invalid_eoc;
|
||||
len = dp - tdp - 2;
|
||||
} else {
|
||||
if (dp < len && (op & ASN1_OP_END__OF)) {
|
||||
datalen = len;
|
||||
csp++;
|
||||
pc = machine[pc + 1];
|
||||
pr_debug("- continue\n");
|
||||
goto next_op;
|
||||
}
|
||||
if (dp != len)
|
||||
goto cons_length_error;
|
||||
len -= tdp;
|
||||
pr_debug("- cons len l=%zu d=%zu\n", len, dp - tdp);
|
||||
}
|
||||
|
||||
if (op & ASN1_OP_END__ACT) {
|
||||
unsigned char act;
|
||||
if (op & ASN1_OP_END__OF)
|
||||
act = machine[pc + 2];
|
||||
else
|
||||
act = machine[pc + 1];
|
||||
ret = actions[act](context, hdr, 0, data + tdp, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
pc += asn1_op_lengths[op];
|
||||
goto next_op;
|
||||
|
||||
case ASN1_OP_MAYBE_ACT:
|
||||
if (!(flags & FLAG_LAST_MATCHED)) {
|
||||
pc += asn1_op_lengths[op];
|
||||
goto next_op;
|
||||
}
|
||||
/* fall through */
|
||||
|
||||
case ASN1_OP_ACT:
|
||||
ret = actions[machine[pc + 1]](context, hdr, tag, data + tdp, len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
pc += asn1_op_lengths[op];
|
||||
goto next_op;
|
||||
|
||||
case ASN1_OP_RETURN:
|
||||
if (unlikely(jsp <= 0))
|
||||
goto jump_stack_underflow;
|
||||
pc = jump_stack[--jsp];
|
||||
flags |= FLAG_MATCHED | FLAG_LAST_MATCHED;
|
||||
goto next_op;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Shouldn't reach here */
|
||||
pr_err("ASN.1 decoder error: Found reserved opcode (%u) pc=%zu\n",
|
||||
op, pc);
|
||||
return -EBADMSG;
|
||||
|
||||
data_overrun_error:
|
||||
errmsg = "Data overrun error";
|
||||
goto error;
|
||||
machine_overrun_error:
|
||||
errmsg = "Machine overrun error";
|
||||
goto error;
|
||||
jump_stack_underflow:
|
||||
errmsg = "Jump stack underflow";
|
||||
goto error;
|
||||
jump_stack_overflow:
|
||||
errmsg = "Jump stack overflow";
|
||||
goto error;
|
||||
cons_stack_underflow:
|
||||
errmsg = "Cons stack underflow";
|
||||
goto error;
|
||||
cons_stack_overflow:
|
||||
errmsg = "Cons stack overflow";
|
||||
goto error;
|
||||
cons_length_error:
|
||||
errmsg = "Cons length error";
|
||||
goto error;
|
||||
missing_eoc:
|
||||
errmsg = "Missing EOC in indefinite len cons";
|
||||
goto error;
|
||||
invalid_eoc:
|
||||
errmsg = "Invalid length EOC";
|
||||
goto error;
|
||||
length_too_long:
|
||||
errmsg = "Unsupported length";
|
||||
goto error;
|
||||
indefinite_len_primitive:
|
||||
errmsg = "Indefinite len primitive not permitted";
|
||||
goto error;
|
||||
tag_mismatch:
|
||||
errmsg = "Unexpected tag";
|
||||
goto error;
|
||||
long_tag_not_supported:
|
||||
errmsg = "Long tag not supported";
|
||||
error:
|
||||
pr_debug("\nASN1: %s [m=%zu d=%zu ot=%02x t=%02x l=%zu]\n",
|
||||
errmsg, pc, dp, optag, tag, len);
|
||||
return -EBADMSG;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asn1_ber_decoder);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
52
lib/crypto/Kconfig
Normal file
52
lib/crypto/Kconfig
Normal file
|
@ -0,0 +1,52 @@
|
|||
menuconfig ASYMMETRIC_KEY_TYPE
|
||||
bool "Asymmetric (public-key cryptographic) key Support"
|
||||
help
|
||||
This option provides support for a key type that holds the data for
|
||||
the asymmetric keys used for public key cryptographic operations such
|
||||
as encryption, decryption, signature generation and signature
|
||||
verification.
|
||||
|
||||
if ASYMMETRIC_KEY_TYPE
|
||||
|
||||
config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
bool "Asymmetric public-key crypto algorithm subtype"
|
||||
help
|
||||
This option provides support for asymmetric public key type handling.
|
||||
If signature generation and/or verification are to be used,
|
||||
appropriate hash algorithms (such as SHA-1) must be available.
|
||||
ENOPKG will be reported if the requisite algorithm is unavailable.
|
||||
|
||||
config RSA_PUBLIC_KEY_PARSER
|
||||
bool "RSA public key parser"
|
||||
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
select ASN1_DECODER
|
||||
select ASN1_COMPILER
|
||||
select OID_REGISTRY
|
||||
help
|
||||
This option provides support for parsing a blob containing RSA
|
||||
public key data and provides the ability to instantiate a public
|
||||
key.
|
||||
|
||||
config X509_CERTIFICATE_PARSER
|
||||
bool "X.509 certificate parser"
|
||||
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
select ASN1_DECODER
|
||||
select ASN1_COMPILER
|
||||
select OID_REGISTRY
|
||||
select LIB_DATE
|
||||
help
|
||||
This option provides support for parsing X.509 format blobs for key
|
||||
data and provides the ability to instantiate a crypto key from a
|
||||
public key packet found inside the certificate.
|
||||
|
||||
config PKCS7_MESSAGE_PARSER
|
||||
bool "PKCS#7 message parser"
|
||||
depends on X509_CERTIFICATE_PARSER
|
||||
select ASN1_DECODER
|
||||
select ASN1_COMPILER
|
||||
select OID_REGISTRY
|
||||
help
|
||||
This option provides support for parsing PKCS#7 format messages for
|
||||
signature data and provides the ability to verify the signature.
|
||||
|
||||
endif # ASYMMETRIC_KEY_TYPE
|
49
lib/crypto/Makefile
Normal file
49
lib/crypto/Makefile
Normal file
|
@ -0,0 +1,49 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Makefile for asymmetric cryptographic keys
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
|
||||
|
||||
asymmetric_keys-y := asymmetric_type.o
|
||||
|
||||
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
|
||||
|
||||
#
|
||||
# RSA public key parser
|
||||
#
|
||||
obj-$(CONFIG_RSA_PUBLIC_KEY_PARSER) += rsa_public_key.o
|
||||
rsa_public_key-y := \
|
||||
rsapubkey.asn1.o \
|
||||
rsa_helper.o
|
||||
|
||||
$(obj)/rsapubkey.asn1.o: $(obj)/rsapubkey.asn1.c $(obj)/rsapubkey.asn1.h
|
||||
$(obj)/rsa_helper.o: $(obj)/rsapubkey.asn1.h
|
||||
|
||||
#
|
||||
# X.509 Certificate handling
|
||||
#
|
||||
obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
|
||||
x509_key_parser-y := \
|
||||
x509.asn1.o \
|
||||
x509_akid.asn1.o \
|
||||
x509_cert_parser.o \
|
||||
x509_public_key.o
|
||||
|
||||
$(obj)/x509_cert_parser.o: \
|
||||
$(obj)/x509.asn1.h \
|
||||
$(obj)/x509_akid.asn1.h
|
||||
|
||||
$(obj)/x509.asn1.o: $(obj)/x509.asn1.c $(obj)/x509.asn1.h
|
||||
$(obj)/x509_akid.asn1.o: $(obj)/x509_akid.asn1.c $(obj)/x509_akid.asn1.h
|
||||
|
||||
#
|
||||
# PKCS#7 message handling
|
||||
#
|
||||
obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
|
||||
pkcs7_message-y := \
|
||||
pkcs7.asn1.o \
|
||||
pkcs7_parser.o
|
||||
|
||||
$(obj)/pkcs7_parser.o: $(obj)/pkcs7.asn1.h
|
||||
$(obj)/pkcs7.asn1.o: $(obj)/pkcs7.asn1.c $(obj)/pkcs7.asn1.h
|
668
lib/crypto/asymmetric_type.c
Normal file
668
lib/crypto/asymmetric_type.c
Normal file
|
@ -0,0 +1,668 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Asymmetric public-key cryptography key type
|
||||
*
|
||||
* See Documentation/crypto/asymmetric-keys.txt
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
#ifndef __UBOOT__
|
||||
#include <keys/asymmetric-subtype.h>
|
||||
#include <keys/asymmetric-parser.h>
|
||||
#endif
|
||||
#include <crypto/public_key.h>
|
||||
#ifdef __UBOOT__
|
||||
#include <linux/compat.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
#else
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ctype.h>
|
||||
#endif
|
||||
#ifdef __UBOOT__
|
||||
#include <keys/asymmetric-type.h>
|
||||
#else
|
||||
#include <keys/system_keyring.h>
|
||||
#include <keys/user-type.h>
|
||||
#include "asymmetric_keys.h"
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifndef __UBOOT__
|
||||
const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
|
||||
[VERIFYING_MODULE_SIGNATURE] = "mod sig",
|
||||
[VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig",
|
||||
[VERIFYING_KEXEC_PE_SIGNATURE] = "kexec PE sig",
|
||||
[VERIFYING_KEY_SIGNATURE] = "key sig",
|
||||
[VERIFYING_KEY_SELF_SIGNATURE] = "key self sig",
|
||||
[VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig",
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(key_being_used_for);
|
||||
|
||||
static LIST_HEAD(asymmetric_key_parsers);
|
||||
static DECLARE_RWSEM(asymmetric_key_parsers_sem);
|
||||
|
||||
/**
|
||||
* find_asymmetric_key - Find a key by ID.
|
||||
* @keyring: The keys to search.
|
||||
* @id_0: The first ID to look for or NULL.
|
||||
* @id_1: The second ID to look for or NULL.
|
||||
* @partial: Use partial match if true, exact if false.
|
||||
*
|
||||
* Find a key in the given keyring by identifier. The preferred identifier is
|
||||
* the id_0 and the fallback identifier is the id_1. If both are given, the
|
||||
* lookup is by the former, but the latter must also match.
|
||||
*/
|
||||
struct key *find_asymmetric_key(struct key *keyring,
|
||||
const struct asymmetric_key_id *id_0,
|
||||
const struct asymmetric_key_id *id_1,
|
||||
bool partial)
|
||||
{
|
||||
struct key *key;
|
||||
key_ref_t ref;
|
||||
const char *lookup;
|
||||
char *req, *p;
|
||||
int len;
|
||||
|
||||
BUG_ON(!id_0 && !id_1);
|
||||
|
||||
if (id_0) {
|
||||
lookup = id_0->data;
|
||||
len = id_0->len;
|
||||
} else {
|
||||
lookup = id_1->data;
|
||||
len = id_1->len;
|
||||
}
|
||||
|
||||
/* Construct an identifier "id:<keyid>". */
|
||||
p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
|
||||
if (!req)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (partial) {
|
||||
*p++ = 'i';
|
||||
*p++ = 'd';
|
||||
} else {
|
||||
*p++ = 'e';
|
||||
*p++ = 'x';
|
||||
}
|
||||
*p++ = ':';
|
||||
p = bin2hex(p, lookup, len);
|
||||
*p = 0;
|
||||
|
||||
pr_debug("Look up: \"%s\"\n", req);
|
||||
|
||||
ref = keyring_search(make_key_ref(keyring, 1),
|
||||
&key_type_asymmetric, req, true);
|
||||
if (IS_ERR(ref))
|
||||
pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
|
||||
kfree(req);
|
||||
|
||||
if (IS_ERR(ref)) {
|
||||
switch (PTR_ERR(ref)) {
|
||||
/* Hide some search errors */
|
||||
case -EACCES:
|
||||
case -ENOTDIR:
|
||||
case -EAGAIN:
|
||||
return ERR_PTR(-ENOKEY);
|
||||
default:
|
||||
return ERR_CAST(ref);
|
||||
}
|
||||
}
|
||||
|
||||
key = key_ref_to_ptr(ref);
|
||||
if (id_0 && id_1) {
|
||||
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
|
||||
|
||||
if (!kids->id[1]) {
|
||||
pr_debug("First ID matches, but second is missing\n");
|
||||
goto reject;
|
||||
}
|
||||
if (!asymmetric_key_id_same(id_1, kids->id[1])) {
|
||||
pr_debug("First ID matches, but second does not\n");
|
||||
goto reject;
|
||||
}
|
||||
}
|
||||
|
||||
pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
|
||||
return key;
|
||||
|
||||
reject:
|
||||
key_put(key);
|
||||
return ERR_PTR(-EKEYREJECTED);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(find_asymmetric_key);
|
||||
#endif /* !__UBOOT__ */
|
||||
|
||||
/**
|
||||
* asymmetric_key_generate_id: Construct an asymmetric key ID
|
||||
* @val_1: First binary blob
|
||||
* @len_1: Length of first binary blob
|
||||
* @val_2: Second binary blob
|
||||
* @len_2: Length of second binary blob
|
||||
*
|
||||
* Construct an asymmetric key ID from a pair of binary blobs.
|
||||
*/
|
||||
struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
|
||||
size_t len_1,
|
||||
const void *val_2,
|
||||
size_t len_2)
|
||||
{
|
||||
struct asymmetric_key_id *kid;
|
||||
|
||||
kid = kmalloc(sizeof(struct asymmetric_key_id) + len_1 + len_2,
|
||||
GFP_KERNEL);
|
||||
if (!kid)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
kid->len = len_1 + len_2;
|
||||
memcpy(kid->data, val_1, len_1);
|
||||
memcpy(kid->data + len_1, val_2, len_2);
|
||||
return kid;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asymmetric_key_generate_id);
|
||||
|
||||
/**
|
||||
* asymmetric_key_id_same - Return true if two asymmetric keys IDs are the same.
|
||||
* @kid_1, @kid_2: The key IDs to compare
|
||||
*/
|
||||
bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
|
||||
const struct asymmetric_key_id *kid2)
|
||||
{
|
||||
if (!kid1 || !kid2)
|
||||
return false;
|
||||
if (kid1->len != kid2->len)
|
||||
return false;
|
||||
return memcmp(kid1->data, kid2->data, kid1->len) == 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
|
||||
|
||||
/**
|
||||
* asymmetric_key_id_partial - Return true if two asymmetric keys IDs
|
||||
* partially match
|
||||
* @kid_1, @kid_2: The key IDs to compare
|
||||
*/
|
||||
bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
|
||||
const struct asymmetric_key_id *kid2)
|
||||
{
|
||||
if (!kid1 || !kid2)
|
||||
return false;
|
||||
if (kid1->len < kid2->len)
|
||||
return false;
|
||||
return memcmp(kid1->data + (kid1->len - kid2->len),
|
||||
kid2->data, kid2->len) == 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/**
|
||||
* asymmetric_match_key_ids - Search asymmetric key IDs
|
||||
* @kids: The list of key IDs to check
|
||||
* @match_id: The key ID we're looking for
|
||||
* @match: The match function to use
|
||||
*/
|
||||
static bool asymmetric_match_key_ids(
|
||||
const struct asymmetric_key_ids *kids,
|
||||
const struct asymmetric_key_id *match_id,
|
||||
bool (*match)(const struct asymmetric_key_id *kid1,
|
||||
const struct asymmetric_key_id *kid2))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!kids || !match_id)
|
||||
return false;
|
||||
for (i = 0; i < ARRAY_SIZE(kids->id); i++)
|
||||
if (match(kids->id[i], match_id))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* helper function can be called directly with pre-allocated memory */
|
||||
inline int __asymmetric_key_hex_to_key_id(const char *id,
|
||||
struct asymmetric_key_id *match_id,
|
||||
size_t hexlen)
|
||||
{
|
||||
match_id->len = hexlen;
|
||||
return hex2bin(match_id->data, id, hexlen);
|
||||
}
|
||||
|
||||
/**
|
||||
* asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
|
||||
* @id: The ID as a hex string.
|
||||
*/
|
||||
struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
|
||||
{
|
||||
struct asymmetric_key_id *match_id;
|
||||
size_t asciihexlen;
|
||||
int ret;
|
||||
|
||||
if (!*id)
|
||||
return ERR_PTR(-EINVAL);
|
||||
asciihexlen = strlen(id);
|
||||
if (asciihexlen & 1)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
match_id = kmalloc(sizeof(struct asymmetric_key_id) + asciihexlen / 2,
|
||||
GFP_KERNEL);
|
||||
if (!match_id)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ret = __asymmetric_key_hex_to_key_id(id, match_id, asciihexlen / 2);
|
||||
if (ret < 0) {
|
||||
kfree(match_id);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
return match_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Match asymmetric keys by an exact match on an ID.
|
||||
*/
|
||||
static bool asymmetric_key_cmp(const struct key *key,
|
||||
const struct key_match_data *match_data)
|
||||
{
|
||||
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
|
||||
const struct asymmetric_key_id *match_id = match_data->preparsed;
|
||||
|
||||
return asymmetric_match_key_ids(kids, match_id,
|
||||
asymmetric_key_id_same);
|
||||
}
|
||||
|
||||
/*
|
||||
* Match asymmetric keys by a partial match on an IDs.
|
||||
*/
|
||||
static bool asymmetric_key_cmp_partial(const struct key *key,
|
||||
const struct key_match_data *match_data)
|
||||
{
|
||||
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
|
||||
const struct asymmetric_key_id *match_id = match_data->preparsed;
|
||||
|
||||
return asymmetric_match_key_ids(kids, match_id,
|
||||
asymmetric_key_id_partial);
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparse the match criterion. If we don't set lookup_type and cmp,
|
||||
* the default will be an exact match on the key description.
|
||||
*
|
||||
* There are some specifiers for matching key IDs rather than by the key
|
||||
* description:
|
||||
*
|
||||
* "id:<id>" - find a key by partial match on any available ID
|
||||
* "ex:<id>" - find a key by exact match on any available ID
|
||||
*
|
||||
* These have to be searched by iteration rather than by direct lookup because
|
||||
* the key is hashed according to its description.
|
||||
*/
|
||||
static int asymmetric_key_match_preparse(struct key_match_data *match_data)
|
||||
{
|
||||
struct asymmetric_key_id *match_id;
|
||||
const char *spec = match_data->raw_data;
|
||||
const char *id;
|
||||
bool (*cmp)(const struct key *, const struct key_match_data *) =
|
||||
asymmetric_key_cmp;
|
||||
|
||||
if (!spec || !*spec)
|
||||
return -EINVAL;
|
||||
if (spec[0] == 'i' &&
|
||||
spec[1] == 'd' &&
|
||||
spec[2] == ':') {
|
||||
id = spec + 3;
|
||||
cmp = asymmetric_key_cmp_partial;
|
||||
} else if (spec[0] == 'e' &&
|
||||
spec[1] == 'x' &&
|
||||
spec[2] == ':') {
|
||||
id = spec + 3;
|
||||
} else {
|
||||
goto default_match;
|
||||
}
|
||||
|
||||
match_id = asymmetric_key_hex_to_key_id(id);
|
||||
if (IS_ERR(match_id))
|
||||
return PTR_ERR(match_id);
|
||||
|
||||
match_data->preparsed = match_id;
|
||||
match_data->cmp = cmp;
|
||||
match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
|
||||
return 0;
|
||||
|
||||
default_match:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the preparsed the match criterion.
|
||||
*/
|
||||
static void asymmetric_key_match_free(struct key_match_data *match_data)
|
||||
{
|
||||
kfree(match_data->preparsed);
|
||||
}
|
||||
|
||||
/*
|
||||
* Describe the asymmetric key
|
||||
*/
|
||||
static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
|
||||
{
|
||||
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
|
||||
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
|
||||
const struct asymmetric_key_id *kid;
|
||||
const unsigned char *p;
|
||||
int n;
|
||||
|
||||
seq_puts(m, key->description);
|
||||
|
||||
if (subtype) {
|
||||
seq_puts(m, ": ");
|
||||
subtype->describe(key, m);
|
||||
|
||||
if (kids && kids->id[1]) {
|
||||
kid = kids->id[1];
|
||||
seq_putc(m, ' ');
|
||||
n = kid->len;
|
||||
p = kid->data;
|
||||
if (n > 4) {
|
||||
p += n - 4;
|
||||
n = 4;
|
||||
}
|
||||
seq_printf(m, "%*phN", n, p);
|
||||
}
|
||||
|
||||
seq_puts(m, " [");
|
||||
/* put something here to indicate the key's capabilities */
|
||||
seq_putc(m, ']');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparse a asymmetric payload to get format the contents appropriately for the
|
||||
* internal payload to cut down on the number of scans of the data performed.
|
||||
*
|
||||
* We also generate a proposed description from the contents of the key that
|
||||
* can be used to name the key if the user doesn't want to provide one.
|
||||
*/
|
||||
static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct asymmetric_key_parser *parser;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
if (prep->datalen == 0)
|
||||
return -EINVAL;
|
||||
|
||||
down_read(&asymmetric_key_parsers_sem);
|
||||
|
||||
ret = -EBADMSG;
|
||||
list_for_each_entry(parser, &asymmetric_key_parsers, link) {
|
||||
pr_debug("Trying parser '%s'\n", parser->name);
|
||||
|
||||
ret = parser->parse(prep);
|
||||
if (ret != -EBADMSG) {
|
||||
pr_debug("Parser recognised the format (ret %d)\n",
|
||||
ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
up_read(&asymmetric_key_parsers_sem);
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up the key ID list
|
||||
*/
|
||||
static void asymmetric_key_free_kids(struct asymmetric_key_ids *kids)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (kids) {
|
||||
for (i = 0; i < ARRAY_SIZE(kids->id); i++)
|
||||
kfree(kids->id[i]);
|
||||
kfree(kids);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up the preparse data
|
||||
*/
|
||||
static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct asymmetric_key_subtype *subtype = prep->payload.data[asym_subtype];
|
||||
struct asymmetric_key_ids *kids = prep->payload.data[asym_key_ids];
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
if (subtype) {
|
||||
subtype->destroy(prep->payload.data[asym_crypto],
|
||||
prep->payload.data[asym_auth]);
|
||||
module_put(subtype->owner);
|
||||
}
|
||||
asymmetric_key_free_kids(kids);
|
||||
kfree(prep->description);
|
||||
}
|
||||
|
||||
/*
|
||||
* dispose of the data dangling from the corpse of a asymmetric key
|
||||
*/
|
||||
static void asymmetric_key_destroy(struct key *key)
|
||||
{
|
||||
struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
|
||||
struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
|
||||
void *data = key->payload.data[asym_crypto];
|
||||
void *auth = key->payload.data[asym_auth];
|
||||
|
||||
key->payload.data[asym_crypto] = NULL;
|
||||
key->payload.data[asym_subtype] = NULL;
|
||||
key->payload.data[asym_key_ids] = NULL;
|
||||
key->payload.data[asym_auth] = NULL;
|
||||
|
||||
if (subtype) {
|
||||
subtype->destroy(data, auth);
|
||||
module_put(subtype->owner);
|
||||
}
|
||||
|
||||
asymmetric_key_free_kids(kids);
|
||||
}
|
||||
|
||||
static struct key_restriction *asymmetric_restriction_alloc(
|
||||
key_restrict_link_func_t check,
|
||||
struct key *key)
|
||||
{
|
||||
struct key_restriction *keyres =
|
||||
kzalloc(sizeof(struct key_restriction), GFP_KERNEL);
|
||||
|
||||
if (!keyres)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
keyres->check = check;
|
||||
keyres->key = key;
|
||||
keyres->keytype = &key_type_asymmetric;
|
||||
|
||||
return keyres;
|
||||
}
|
||||
|
||||
/*
|
||||
* look up keyring restrict functions for asymmetric keys
|
||||
*/
|
||||
static struct key_restriction *asymmetric_lookup_restriction(
|
||||
const char *restriction)
|
||||
{
|
||||
char *restrict_method;
|
||||
char *parse_buf;
|
||||
char *next;
|
||||
struct key_restriction *ret = ERR_PTR(-EINVAL);
|
||||
|
||||
if (strcmp("builtin_trusted", restriction) == 0)
|
||||
return asymmetric_restriction_alloc(
|
||||
restrict_link_by_builtin_trusted, NULL);
|
||||
|
||||
if (strcmp("builtin_and_secondary_trusted", restriction) == 0)
|
||||
return asymmetric_restriction_alloc(
|
||||
restrict_link_by_builtin_and_secondary_trusted, NULL);
|
||||
|
||||
parse_buf = kstrndup(restriction, PAGE_SIZE, GFP_KERNEL);
|
||||
if (!parse_buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
next = parse_buf;
|
||||
restrict_method = strsep(&next, ":");
|
||||
|
||||
if ((strcmp(restrict_method, "key_or_keyring") == 0) && next) {
|
||||
char *key_text;
|
||||
key_serial_t serial;
|
||||
struct key *key;
|
||||
key_restrict_link_func_t link_fn =
|
||||
restrict_link_by_key_or_keyring;
|
||||
bool allow_null_key = false;
|
||||
|
||||
key_text = strsep(&next, ":");
|
||||
|
||||
if (next) {
|
||||
if (strcmp(next, "chain") != 0)
|
||||
goto out;
|
||||
|
||||
link_fn = restrict_link_by_key_or_keyring_chain;
|
||||
allow_null_key = true;
|
||||
}
|
||||
|
||||
if (kstrtos32(key_text, 0, &serial) < 0)
|
||||
goto out;
|
||||
|
||||
if ((serial == 0) && allow_null_key) {
|
||||
key = NULL;
|
||||
} else {
|
||||
key = key_lookup(serial);
|
||||
if (IS_ERR(key)) {
|
||||
ret = ERR_CAST(key);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = asymmetric_restriction_alloc(link_fn, key);
|
||||
if (IS_ERR(ret))
|
||||
key_put(key);
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(parse_buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int asymmetric_key_eds_op(struct kernel_pkey_params *params,
|
||||
const void *in, void *out)
|
||||
{
|
||||
const struct asymmetric_key_subtype *subtype;
|
||||
struct key *key = params->key;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
if (key->type != &key_type_asymmetric)
|
||||
return -EINVAL;
|
||||
subtype = asymmetric_key_subtype(key);
|
||||
if (!subtype ||
|
||||
!key->payload.data[0])
|
||||
return -EINVAL;
|
||||
if (!subtype->eds_op)
|
||||
return -ENOTSUPP;
|
||||
|
||||
ret = subtype->eds_op(params, in, out);
|
||||
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
|
||||
const void *in, const void *in2)
|
||||
{
|
||||
struct public_key_signature sig = {
|
||||
.s_size = params->in2_len,
|
||||
.digest_size = params->in_len,
|
||||
.encoding = params->encoding,
|
||||
.hash_algo = params->hash_algo,
|
||||
.digest = (void *)in,
|
||||
.s = (void *)in2,
|
||||
};
|
||||
|
||||
return verify_signature(params->key, &sig);
|
||||
}
|
||||
|
||||
struct key_type key_type_asymmetric = {
|
||||
.name = "asymmetric",
|
||||
.preparse = asymmetric_key_preparse,
|
||||
.free_preparse = asymmetric_key_free_preparse,
|
||||
.instantiate = generic_key_instantiate,
|
||||
.match_preparse = asymmetric_key_match_preparse,
|
||||
.match_free = asymmetric_key_match_free,
|
||||
.destroy = asymmetric_key_destroy,
|
||||
.describe = asymmetric_key_describe,
|
||||
.lookup_restriction = asymmetric_lookup_restriction,
|
||||
.asym_query = query_asymmetric_key,
|
||||
.asym_eds_op = asymmetric_key_eds_op,
|
||||
.asym_verify_signature = asymmetric_key_verify_signature,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(key_type_asymmetric);
|
||||
|
||||
/**
|
||||
* register_asymmetric_key_parser - Register a asymmetric key blob parser
|
||||
* @parser: The parser to register
|
||||
*/
|
||||
int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
|
||||
{
|
||||
struct asymmetric_key_parser *cursor;
|
||||
int ret;
|
||||
|
||||
down_write(&asymmetric_key_parsers_sem);
|
||||
|
||||
list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
|
||||
if (strcmp(cursor->name, parser->name) == 0) {
|
||||
pr_err("Asymmetric key parser '%s' already registered\n",
|
||||
parser->name);
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&parser->link, &asymmetric_key_parsers);
|
||||
|
||||
pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
up_write(&asymmetric_key_parsers_sem);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
|
||||
|
||||
/**
|
||||
* unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
|
||||
* @parser: The parser to unregister
|
||||
*/
|
||||
void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
|
||||
{
|
||||
down_write(&asymmetric_key_parsers_sem);
|
||||
list_del(&parser->link);
|
||||
up_write(&asymmetric_key_parsers_sem);
|
||||
|
||||
pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
|
||||
|
||||
/*
|
||||
* Module stuff
|
||||
*/
|
||||
static int __init asymmetric_key_init(void)
|
||||
{
|
||||
return register_key_type(&key_type_asymmetric);
|
||||
}
|
||||
|
||||
static void __exit asymmetric_key_cleanup(void)
|
||||
{
|
||||
unregister_key_type(&key_type_asymmetric);
|
||||
}
|
||||
|
||||
module_init(asymmetric_key_init);
|
||||
module_exit(asymmetric_key_cleanup);
|
||||
#endif /* !__UBOOT__ */
|
135
lib/crypto/pkcs7.asn1
Normal file
135
lib/crypto/pkcs7.asn1
Normal file
|
@ -0,0 +1,135 @@
|
|||
PKCS7ContentInfo ::= SEQUENCE {
|
||||
contentType ContentType ({ pkcs7_check_content_type }),
|
||||
content [0] EXPLICIT SignedData OPTIONAL
|
||||
}
|
||||
|
||||
ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
|
||||
|
||||
SignedData ::= SEQUENCE {
|
||||
version INTEGER ({ pkcs7_note_signeddata_version }),
|
||||
digestAlgorithms DigestAlgorithmIdentifiers,
|
||||
contentInfo ContentInfo ({ pkcs7_note_content }),
|
||||
certificates CHOICE {
|
||||
certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
|
||||
certSequence [2] IMPLICIT Certificates
|
||||
} OPTIONAL ({ pkcs7_note_certificate_list }),
|
||||
crls CHOICE {
|
||||
crlSet [1] IMPLICIT CertificateRevocationLists,
|
||||
crlSequence [3] IMPLICIT CRLSequence
|
||||
} OPTIONAL,
|
||||
signerInfos SignerInfos
|
||||
}
|
||||
|
||||
ContentInfo ::= SEQUENCE {
|
||||
contentType ContentType ({ pkcs7_note_OID }),
|
||||
content [0] EXPLICIT Data OPTIONAL
|
||||
}
|
||||
|
||||
Data ::= ANY ({ pkcs7_note_data })
|
||||
|
||||
DigestAlgorithmIdentifiers ::= CHOICE {
|
||||
daSet SET OF DigestAlgorithmIdentifier,
|
||||
daSequence SEQUENCE OF DigestAlgorithmIdentifier
|
||||
}
|
||||
|
||||
DigestAlgorithmIdentifier ::= SEQUENCE {
|
||||
algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
|
||||
parameters ANY OPTIONAL
|
||||
}
|
||||
|
||||
--
|
||||
-- Certificates and certificate lists
|
||||
--
|
||||
ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate
|
||||
|
||||
ExtendedCertificateOrCertificate ::= CHOICE {
|
||||
certificate Certificate, -- X.509
|
||||
extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6
|
||||
}
|
||||
|
||||
ExtendedCertificate ::= Certificate -- cheating
|
||||
|
||||
Certificates ::= SEQUENCE OF Certificate
|
||||
|
||||
CertificateRevocationLists ::= SET OF CertificateList
|
||||
|
||||
CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly
|
||||
|
||||
CRLSequence ::= SEQUENCE OF CertificateList
|
||||
|
||||
Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509
|
||||
|
||||
--
|
||||
-- Signer information
|
||||
--
|
||||
SignerInfos ::= CHOICE {
|
||||
siSet SET OF SignerInfo,
|
||||
siSequence SEQUENCE OF SignerInfo
|
||||
}
|
||||
|
||||
SignerInfo ::= SEQUENCE {
|
||||
version INTEGER ({ pkcs7_note_signerinfo_version }),
|
||||
sid SignerIdentifier, -- CMS variant, not PKCS#7
|
||||
digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }),
|
||||
authenticatedAttributes CHOICE {
|
||||
aaSet [0] IMPLICIT SetOfAuthenticatedAttribute
|
||||
({ pkcs7_sig_note_set_of_authattrs }),
|
||||
aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute
|
||||
-- Explicit because easier to compute digest on
|
||||
-- sequence of attributes and then reuse encoded
|
||||
-- sequence in aaSequence.
|
||||
} OPTIONAL,
|
||||
digestEncryptionAlgorithm
|
||||
DigestEncryptionAlgorithmIdentifier ({ pkcs7_sig_note_pkey_algo }),
|
||||
encryptedDigest EncryptedDigest,
|
||||
unauthenticatedAttributes CHOICE {
|
||||
uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute,
|
||||
uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute
|
||||
} OPTIONAL
|
||||
} ({ pkcs7_note_signed_info })
|
||||
|
||||
SignerIdentifier ::= CHOICE {
|
||||
-- RFC5652 sec 5.3
|
||||
issuerAndSerialNumber IssuerAndSerialNumber,
|
||||
subjectKeyIdentifier [0] IMPLICIT SubjectKeyIdentifier
|
||||
}
|
||||
|
||||
IssuerAndSerialNumber ::= SEQUENCE {
|
||||
issuer Name ({ pkcs7_sig_note_issuer }),
|
||||
serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial })
|
||||
}
|
||||
|
||||
CertificateSerialNumber ::= INTEGER
|
||||
|
||||
SubjectKeyIdentifier ::= OCTET STRING ({ pkcs7_sig_note_skid })
|
||||
|
||||
SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute
|
||||
|
||||
AuthenticatedAttribute ::= SEQUENCE {
|
||||
type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
|
||||
values SET OF ANY ({ pkcs7_sig_note_authenticated_attr })
|
||||
}
|
||||
|
||||
UnauthenticatedAttribute ::= SEQUENCE {
|
||||
type OBJECT IDENTIFIER,
|
||||
values SET OF ANY
|
||||
}
|
||||
|
||||
DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
|
||||
algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
|
||||
parameters ANY OPTIONAL
|
||||
}
|
||||
|
||||
EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature })
|
||||
|
||||
---
|
||||
--- X.500 Name
|
||||
---
|
||||
Name ::= SEQUENCE OF RelativeDistinguishedName
|
||||
|
||||
RelativeDistinguishedName ::= SET OF AttributeValueAssertion
|
||||
|
||||
AttributeValueAssertion ::= SEQUENCE {
|
||||
attributeType OBJECT IDENTIFIER ({ pkcs7_note_OID }),
|
||||
attributeValue ANY
|
||||
}
|
693
lib/crypto/pkcs7_parser.c
Normal file
693
lib/crypto/pkcs7_parser.c
Normal file
|
@ -0,0 +1,693 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* PKCS#7 parser
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "PKCS7: "fmt
|
||||
#ifdef __UBOOT__
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/compat.h>
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#endif
|
||||
#include <linux/err.h>
|
||||
#include <linux/oid_registry.h>
|
||||
#include <crypto/public_key.h>
|
||||
#include "pkcs7_parser.h"
|
||||
#include "pkcs7.asn1.h"
|
||||
|
||||
MODULE_DESCRIPTION("PKCS#7 parser");
|
||||
MODULE_AUTHOR("Red Hat, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct pkcs7_parse_context {
|
||||
struct pkcs7_message *msg; /* Message being constructed */
|
||||
struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */
|
||||
struct pkcs7_signed_info **ppsinfo;
|
||||
struct x509_certificate *certs; /* Certificate cache */
|
||||
struct x509_certificate **ppcerts;
|
||||
unsigned long data; /* Start of data */
|
||||
enum OID last_oid; /* Last OID encountered */
|
||||
unsigned x509_index;
|
||||
unsigned sinfo_index;
|
||||
const void *raw_serial;
|
||||
unsigned raw_serial_size;
|
||||
unsigned raw_issuer_size;
|
||||
const void *raw_issuer;
|
||||
const void *raw_skid;
|
||||
unsigned raw_skid_size;
|
||||
bool expect_skid;
|
||||
};
|
||||
|
||||
/*
|
||||
* Free a signed information block.
|
||||
*/
|
||||
static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
|
||||
{
|
||||
if (sinfo) {
|
||||
public_key_signature_free(sinfo->sig);
|
||||
kfree(sinfo);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pkcs7_free_message - Free a PKCS#7 message
|
||||
* @pkcs7: The PKCS#7 message to free
|
||||
*/
|
||||
void pkcs7_free_message(struct pkcs7_message *pkcs7)
|
||||
{
|
||||
struct x509_certificate *cert;
|
||||
struct pkcs7_signed_info *sinfo;
|
||||
|
||||
if (pkcs7) {
|
||||
while (pkcs7->certs) {
|
||||
cert = pkcs7->certs;
|
||||
pkcs7->certs = cert->next;
|
||||
x509_free_certificate(cert);
|
||||
}
|
||||
while (pkcs7->crl) {
|
||||
cert = pkcs7->crl;
|
||||
pkcs7->crl = cert->next;
|
||||
x509_free_certificate(cert);
|
||||
}
|
||||
while (pkcs7->signed_infos) {
|
||||
sinfo = pkcs7->signed_infos;
|
||||
pkcs7->signed_infos = sinfo->next;
|
||||
pkcs7_free_signed_info(sinfo);
|
||||
}
|
||||
kfree(pkcs7);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pkcs7_free_message);
|
||||
|
||||
/*
|
||||
* Check authenticatedAttributes are provided or not provided consistently.
|
||||
*/
|
||||
static int pkcs7_check_authattrs(struct pkcs7_message *msg)
|
||||
{
|
||||
struct pkcs7_signed_info *sinfo;
|
||||
bool want = false;
|
||||
|
||||
sinfo = msg->signed_infos;
|
||||
if (!sinfo)
|
||||
goto inconsistent;
|
||||
|
||||
if (sinfo->authattrs) {
|
||||
want = true;
|
||||
msg->have_authattrs = true;
|
||||
}
|
||||
|
||||
for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
|
||||
if (!!sinfo->authattrs != want)
|
||||
goto inconsistent;
|
||||
return 0;
|
||||
|
||||
inconsistent:
|
||||
pr_warn("Inconsistently supplied authAttrs\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* pkcs7_parse_message - Parse a PKCS#7 message
|
||||
* @data: The raw binary ASN.1 encoded message to be parsed
|
||||
* @datalen: The size of the encoded message
|
||||
*/
|
||||
struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx;
|
||||
struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
|
||||
int ret;
|
||||
|
||||
ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
goto out_no_ctx;
|
||||
ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
|
||||
if (!ctx->msg)
|
||||
goto out_no_msg;
|
||||
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
||||
if (!ctx->sinfo)
|
||||
goto out_no_sinfo;
|
||||
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
|
||||
GFP_KERNEL);
|
||||
if (!ctx->sinfo->sig)
|
||||
goto out_no_sig;
|
||||
|
||||
ctx->data = (unsigned long)data;
|
||||
ctx->ppcerts = &ctx->certs;
|
||||
ctx->ppsinfo = &ctx->msg->signed_infos;
|
||||
|
||||
/* Attempt to decode the signature */
|
||||
ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
|
||||
if (ret < 0) {
|
||||
msg = ERR_PTR(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = pkcs7_check_authattrs(ctx->msg);
|
||||
if (ret < 0) {
|
||||
msg = ERR_PTR(ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
msg = ctx->msg;
|
||||
ctx->msg = NULL;
|
||||
|
||||
out:
|
||||
while (ctx->certs) {
|
||||
struct x509_certificate *cert = ctx->certs;
|
||||
ctx->certs = cert->next;
|
||||
x509_free_certificate(cert);
|
||||
}
|
||||
out_no_sig:
|
||||
pkcs7_free_signed_info(ctx->sinfo);
|
||||
out_no_sinfo:
|
||||
pkcs7_free_message(ctx->msg);
|
||||
out_no_msg:
|
||||
kfree(ctx);
|
||||
out_no_ctx:
|
||||
return msg;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pkcs7_parse_message);
|
||||
|
||||
/**
|
||||
* pkcs7_get_content_data - Get access to the PKCS#7 content
|
||||
* @pkcs7: The preparsed PKCS#7 message to access
|
||||
* @_data: Place to return a pointer to the data
|
||||
* @_data_len: Place to return the data length
|
||||
* @_headerlen: Size of ASN.1 header not included in _data
|
||||
*
|
||||
* Get access to the data content of the PKCS#7 message. The size of the
|
||||
* header of the ASN.1 object that contains it is also provided and can be used
|
||||
* to adjust *_data and *_data_len to get the entire object.
|
||||
*
|
||||
* Returns -ENODATA if the data object was missing from the message.
|
||||
*/
|
||||
int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
|
||||
const void **_data, size_t *_data_len,
|
||||
size_t *_headerlen)
|
||||
{
|
||||
if (!pkcs7->data)
|
||||
return -ENODATA;
|
||||
|
||||
*_data = pkcs7->data;
|
||||
*_data_len = pkcs7->data_len;
|
||||
if (_headerlen)
|
||||
*_headerlen = pkcs7->data_hdrlen;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
|
||||
|
||||
/*
|
||||
* Note an OID when we find one for later processing when we know how
|
||||
* to interpret it.
|
||||
*/
|
||||
int pkcs7_note_OID(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
ctx->last_oid = look_up_OID(value, vlen);
|
||||
if (ctx->last_oid == OID__NR) {
|
||||
char buffer[50];
|
||||
sprint_oid(value, vlen, buffer, sizeof(buffer));
|
||||
printk("PKCS7: Unknown OID: [%lu] %s\n",
|
||||
(unsigned long)value - ctx->data, buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the digest algorithm for the signature.
|
||||
*/
|
||||
int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
switch (ctx->last_oid) {
|
||||
case OID_md4:
|
||||
ctx->sinfo->sig->hash_algo = "md4";
|
||||
break;
|
||||
case OID_md5:
|
||||
ctx->sinfo->sig->hash_algo = "md5";
|
||||
break;
|
||||
case OID_sha1:
|
||||
ctx->sinfo->sig->hash_algo = "sha1";
|
||||
break;
|
||||
case OID_sha256:
|
||||
ctx->sinfo->sig->hash_algo = "sha256";
|
||||
break;
|
||||
case OID_sha384:
|
||||
ctx->sinfo->sig->hash_algo = "sha384";
|
||||
break;
|
||||
case OID_sha512:
|
||||
ctx->sinfo->sig->hash_algo = "sha512";
|
||||
break;
|
||||
case OID_sha224:
|
||||
ctx->sinfo->sig->hash_algo = "sha224";
|
||||
break;
|
||||
default:
|
||||
printk("Unsupported digest algo: %u\n", ctx->last_oid);
|
||||
return -ENOPKG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the public key algorithm for the signature.
|
||||
*/
|
||||
int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
switch (ctx->last_oid) {
|
||||
case OID_rsaEncryption:
|
||||
ctx->sinfo->sig->pkey_algo = "rsa";
|
||||
ctx->sinfo->sig->encoding = "pkcs1";
|
||||
break;
|
||||
default:
|
||||
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
|
||||
return -ENOPKG;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We only support signed data [RFC2315 sec 9].
|
||||
*/
|
||||
int pkcs7_check_content_type(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
if (ctx->last_oid != OID_signed_data) {
|
||||
pr_warn("Only support pkcs7_signedData type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the SignedData version
|
||||
*/
|
||||
int pkcs7_note_signeddata_version(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
unsigned version;
|
||||
|
||||
if (vlen != 1)
|
||||
goto unsupported;
|
||||
|
||||
ctx->msg->version = version = *(const u8 *)value;
|
||||
switch (version) {
|
||||
case 1:
|
||||
/* PKCS#7 SignedData [RFC2315 sec 9.1]
|
||||
* CMS ver 1 SignedData [RFC5652 sec 5.1]
|
||||
*/
|
||||
break;
|
||||
case 3:
|
||||
/* CMS ver 3 SignedData [RFC2315 sec 5.1] */
|
||||
break;
|
||||
default:
|
||||
goto unsupported;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unsupported:
|
||||
pr_warn("Unsupported SignedData version\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the SignerInfo version
|
||||
*/
|
||||
int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
unsigned version;
|
||||
|
||||
if (vlen != 1)
|
||||
goto unsupported;
|
||||
|
||||
version = *(const u8 *)value;
|
||||
switch (version) {
|
||||
case 1:
|
||||
/* PKCS#7 SignerInfo [RFC2315 sec 9.2]
|
||||
* CMS ver 1 SignerInfo [RFC5652 sec 5.3]
|
||||
*/
|
||||
if (ctx->msg->version != 1)
|
||||
goto version_mismatch;
|
||||
ctx->expect_skid = false;
|
||||
break;
|
||||
case 3:
|
||||
/* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */
|
||||
if (ctx->msg->version == 1)
|
||||
goto version_mismatch;
|
||||
ctx->expect_skid = true;
|
||||
break;
|
||||
default:
|
||||
goto unsupported;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unsupported:
|
||||
pr_warn("Unsupported SignerInfo version\n");
|
||||
return -EINVAL;
|
||||
version_mismatch:
|
||||
pr_warn("SignedData-SignerInfo version mismatch\n");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract a certificate and store it in the context.
|
||||
*/
|
||||
int pkcs7_extract_cert(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
struct x509_certificate *x509;
|
||||
|
||||
if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
|
||||
pr_debug("Cert began with tag %02x at %lu\n",
|
||||
tag, (unsigned long)ctx - ctx->data);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* We have to correct for the header so that the X.509 parser can start
|
||||
* from the beginning. Note that since X.509 stipulates DER, there
|
||||
* probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
|
||||
* stipulates BER).
|
||||
*/
|
||||
value -= hdrlen;
|
||||
vlen += hdrlen;
|
||||
|
||||
if (((u8*)value)[1] == 0x80)
|
||||
vlen += 2; /* Indefinite length - there should be an EOC */
|
||||
|
||||
x509 = x509_cert_parse(value, vlen);
|
||||
if (IS_ERR(x509))
|
||||
return PTR_ERR(x509);
|
||||
|
||||
x509->index = ++ctx->x509_index;
|
||||
pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
|
||||
pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);
|
||||
|
||||
*ctx->ppcerts = x509;
|
||||
ctx->ppcerts = &x509->next;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the certificate list
|
||||
*/
|
||||
int pkcs7_note_certificate_list(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
pr_devel("Got cert list (%02x)\n", tag);
|
||||
|
||||
*ctx->ppcerts = ctx->msg->certs;
|
||||
ctx->msg->certs = ctx->certs;
|
||||
ctx->certs = NULL;
|
||||
ctx->ppcerts = &ctx->certs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the content type.
|
||||
*/
|
||||
int pkcs7_note_content(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
if (ctx->last_oid != OID_data &&
|
||||
ctx->last_oid != OID_msIndirectData) {
|
||||
pr_warn("Unsupported data type %d\n", ctx->last_oid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx->msg->data_type = ctx->last_oid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the data from the message and store that and its content type OID in
|
||||
* the context.
|
||||
*/
|
||||
int pkcs7_note_data(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
pr_debug("Got data\n");
|
||||
|
||||
ctx->msg->data = value;
|
||||
ctx->msg->data_len = vlen;
|
||||
ctx->msg->data_hdrlen = hdrlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse authenticated attributes.
|
||||
*/
|
||||
int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
||||
enum OID content_type;
|
||||
|
||||
pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
|
||||
|
||||
switch (ctx->last_oid) {
|
||||
case OID_contentType:
|
||||
if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
|
||||
goto repeated;
|
||||
content_type = look_up_OID(value, vlen);
|
||||
if (content_type != ctx->msg->data_type) {
|
||||
pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",
|
||||
ctx->msg->data_type, sinfo->index,
|
||||
content_type);
|
||||
return -EBADMSG;
|
||||
}
|
||||
return 0;
|
||||
|
||||
case OID_signingTime:
|
||||
if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
|
||||
goto repeated;
|
||||
/* Should we check that the signing time is consistent
|
||||
* with the signer's X.509 cert?
|
||||
*/
|
||||
return x509_decode_time(&sinfo->signing_time,
|
||||
hdrlen, tag, value, vlen);
|
||||
|
||||
case OID_messageDigest:
|
||||
if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
|
||||
goto repeated;
|
||||
if (tag != ASN1_OTS)
|
||||
return -EBADMSG;
|
||||
sinfo->msgdigest = value;
|
||||
sinfo->msgdigest_len = vlen;
|
||||
return 0;
|
||||
|
||||
case OID_smimeCapabilites:
|
||||
if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
|
||||
goto repeated;
|
||||
#ifdef __UBOOT__ /* OID_data is needed for authenticated UEFI variables */
|
||||
if (ctx->msg->data_type != OID_msIndirectData &&
|
||||
ctx->msg->data_type != OID_data) {
|
||||
#else
|
||||
if (ctx->msg->data_type != OID_msIndirectData) {
|
||||
#endif
|
||||
pr_warn("S/MIME Caps only allowed with Authenticode\n");
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
return 0;
|
||||
|
||||
/* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE
|
||||
* char URLs and cont[1] 8-bit char URLs.
|
||||
*
|
||||
* Microsoft StatementType seems to contain a list of OIDs that
|
||||
* are also used as extendedKeyUsage types in X.509 certs.
|
||||
*/
|
||||
case OID_msSpOpusInfo:
|
||||
if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
|
||||
goto repeated;
|
||||
goto authenticode_check;
|
||||
case OID_msStatementType:
|
||||
if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
|
||||
goto repeated;
|
||||
authenticode_check:
|
||||
if (ctx->msg->data_type != OID_msIndirectData) {
|
||||
pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
/* I'm not sure how to validate these */
|
||||
return 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
repeated:
|
||||
/* We permit max one item per AuthenticatedAttribute and no repeats */
|
||||
pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
|
||||
*/
|
||||
int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
||||
|
||||
if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
|
||||
!test_bit(sinfo_has_message_digest, &sinfo->aa_set)) {
|
||||
pr_warn("Missing required AuthAttr\n");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
if (ctx->msg->data_type != OID_msIndirectData &&
|
||||
test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) {
|
||||
pr_warn("Unexpected Authenticode AuthAttr\n");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
|
||||
sinfo->authattrs = value - (hdrlen - 1);
|
||||
sinfo->authattrs_len = vlen + (hdrlen - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the issuing certificate serial number
|
||||
*/
|
||||
int pkcs7_sig_note_serial(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
ctx->raw_serial = value;
|
||||
ctx->raw_serial_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the issuer's name
|
||||
*/
|
||||
int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
ctx->raw_issuer = value;
|
||||
ctx->raw_issuer_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the issuing cert's subjectKeyIdentifier
|
||||
*/
|
||||
int pkcs7_sig_note_skid(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
|
||||
|
||||
ctx->raw_skid = value;
|
||||
ctx->raw_skid_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the signature data
|
||||
*/
|
||||
int pkcs7_sig_note_signature(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
|
||||
ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL);
|
||||
if (!ctx->sinfo->sig->s)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->sinfo->sig->s_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note a signature information block
|
||||
*/
|
||||
int pkcs7_note_signed_info(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct pkcs7_parse_context *ctx = context;
|
||||
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
||||
struct asymmetric_key_id *kid;
|
||||
|
||||
if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {
|
||||
pr_warn("Authenticode requires AuthAttrs\n");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* Generate cert issuer + serial number key ID */
|
||||
if (!ctx->expect_skid) {
|
||||
kid = asymmetric_key_generate_id(ctx->raw_serial,
|
||||
ctx->raw_serial_size,
|
||||
ctx->raw_issuer,
|
||||
ctx->raw_issuer_size);
|
||||
} else {
|
||||
kid = asymmetric_key_generate_id(ctx->raw_skid,
|
||||
ctx->raw_skid_size,
|
||||
"", 0);
|
||||
}
|
||||
if (IS_ERR(kid))
|
||||
return PTR_ERR(kid);
|
||||
|
||||
pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
|
||||
|
||||
sinfo->sig->auth_ids[0] = kid;
|
||||
sinfo->index = ++ctx->sinfo_index;
|
||||
*ctx->ppsinfo = sinfo;
|
||||
ctx->ppsinfo = &sinfo->next;
|
||||
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
||||
if (!ctx->sinfo)
|
||||
return -ENOMEM;
|
||||
ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
|
||||
GFP_KERNEL);
|
||||
if (!ctx->sinfo->sig)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
65
lib/crypto/pkcs7_parser.h
Normal file
65
lib/crypto/pkcs7_parser.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* PKCS#7 crypto data parser internal definitions
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/oid_registry.h>
|
||||
#include <crypto/pkcs7.h>
|
||||
#include "x509_parser.h"
|
||||
|
||||
#define kenter(FMT, ...) \
|
||||
pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
|
||||
#define kleave(FMT, ...) \
|
||||
pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
|
||||
|
||||
struct pkcs7_signed_info {
|
||||
struct pkcs7_signed_info *next;
|
||||
struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
|
||||
unsigned index;
|
||||
bool unsupported_crypto; /* T if not usable due to missing crypto */
|
||||
bool blacklisted;
|
||||
|
||||
/* Message digest - the digest of the Content Data (or NULL) */
|
||||
const void *msgdigest;
|
||||
unsigned msgdigest_len;
|
||||
|
||||
/* Authenticated Attribute data (or NULL) */
|
||||
unsigned authattrs_len;
|
||||
const void *authattrs;
|
||||
unsigned long aa_set;
|
||||
#define sinfo_has_content_type 0
|
||||
#define sinfo_has_signing_time 1
|
||||
#define sinfo_has_message_digest 2
|
||||
#define sinfo_has_smime_caps 3
|
||||
#define sinfo_has_ms_opus_info 4
|
||||
#define sinfo_has_ms_statement_type 5
|
||||
time64_t signing_time;
|
||||
|
||||
/* Message signature.
|
||||
*
|
||||
* This contains the generated digest of _either_ the Content Data or
|
||||
* the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
|
||||
* the attributes contains the digest of the the Content Data within
|
||||
* it.
|
||||
*
|
||||
* THis also contains the issuing cert serial number and issuer's name
|
||||
* [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3].
|
||||
*/
|
||||
struct public_key_signature *sig;
|
||||
};
|
||||
|
||||
struct pkcs7_message {
|
||||
struct x509_certificate *certs; /* Certificate list */
|
||||
struct x509_certificate *crl; /* Revocation list */
|
||||
struct pkcs7_signed_info *signed_infos;
|
||||
u8 version; /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */
|
||||
bool have_authattrs; /* T if have authattrs */
|
||||
|
||||
/* Content Data (or NULL) */
|
||||
enum OID data_type; /* Type of Data */
|
||||
size_t data_len; /* Length of Data */
|
||||
size_t data_hdrlen; /* Length of Data ASN.1 header */
|
||||
const void *data; /* Content Data (or 0) */
|
||||
};
|
376
lib/crypto/public_key.c
Normal file
376
lib/crypto/public_key.c
Normal file
|
@ -0,0 +1,376 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* In-software asymmetric public-key crypto subtype
|
||||
*
|
||||
* See Documentation/crypto/asymmetric-keys.txt
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "PKEY: "fmt
|
||||
#ifdef __UBOOT__
|
||||
#include <linux/compat.h>
|
||||
#else
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/slab.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <keys/asymmetric-subtype.h>
|
||||
#endif
|
||||
#include <crypto/public_key.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <crypto/akcipher.h>
|
||||
#endif
|
||||
|
||||
MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
|
||||
MODULE_AUTHOR("Red Hat, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/*
|
||||
* Provide a part of a description of the key for /proc/keys.
|
||||
*/
|
||||
static void public_key_describe(const struct key *asymmetric_key,
|
||||
struct seq_file *m)
|
||||
{
|
||||
struct public_key *key = asymmetric_key->payload.data[asym_crypto];
|
||||
|
||||
if (key)
|
||||
seq_printf(m, "%s.%s", key->id_type, key->pkey_algo);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Destroy a public key algorithm key.
|
||||
*/
|
||||
void public_key_free(struct public_key *key)
|
||||
{
|
||||
if (key) {
|
||||
kfree(key->key);
|
||||
kfree(key->params);
|
||||
kfree(key);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(public_key_free);
|
||||
|
||||
#ifdef __UBOOT__
|
||||
/*
|
||||
* from <linux>/crypto/asymmetric_keys/signature.c
|
||||
*
|
||||
* Destroy a public key signature.
|
||||
*/
|
||||
void public_key_signature_free(struct public_key_signature *sig)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (sig) {
|
||||
for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
|
||||
free(sig->auth_ids[i]);
|
||||
free(sig->s);
|
||||
free(sig->digest);
|
||||
free(sig);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(public_key_signature_free);
|
||||
|
||||
#else
|
||||
/*
|
||||
* Destroy a public key algorithm key.
|
||||
*/
|
||||
static void public_key_destroy(void *payload0, void *payload3)
|
||||
{
|
||||
public_key_free(payload0);
|
||||
public_key_signature_free(payload3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the crypto algorithm name.
|
||||
*/
|
||||
static
|
||||
int software_key_determine_akcipher(const char *encoding,
|
||||
const char *hash_algo,
|
||||
const struct public_key *pkey,
|
||||
char alg_name[CRYPTO_MAX_ALG_NAME])
|
||||
{
|
||||
int n;
|
||||
|
||||
if (strcmp(encoding, "pkcs1") == 0) {
|
||||
/* The data wangled by the RSA algorithm is typically padded
|
||||
* and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
|
||||
* sec 8.2].
|
||||
*/
|
||||
if (!hash_algo)
|
||||
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
|
||||
"pkcs1pad(%s)",
|
||||
pkey->pkey_algo);
|
||||
else
|
||||
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
|
||||
"pkcs1pad(%s,%s)",
|
||||
pkey->pkey_algo, hash_algo);
|
||||
return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
|
||||
}
|
||||
|
||||
if (strcmp(encoding, "raw") == 0) {
|
||||
strcpy(alg_name, pkey->pkey_algo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOPKG;
|
||||
}
|
||||
|
||||
static u8 *pkey_pack_u32(u8 *dst, u32 val)
|
||||
{
|
||||
memcpy(dst, &val, sizeof(val));
|
||||
return dst + sizeof(val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Query information about a key.
|
||||
*/
|
||||
static int software_key_query(const struct kernel_pkey_params *params,
|
||||
struct kernel_pkey_query *info)
|
||||
{
|
||||
struct crypto_akcipher *tfm;
|
||||
struct public_key *pkey = params->key->payload.data[asym_crypto];
|
||||
char alg_name[CRYPTO_MAX_ALG_NAME];
|
||||
u8 *key, *ptr;
|
||||
int ret, len;
|
||||
|
||||
ret = software_key_determine_akcipher(params->encoding,
|
||||
params->hash_algo,
|
||||
pkey, alg_name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tfm = crypto_alloc_akcipher(alg_name, 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
|
||||
GFP_KERNEL);
|
||||
if (!key)
|
||||
goto error_free_tfm;
|
||||
memcpy(key, pkey->key, pkey->keylen);
|
||||
ptr = key + pkey->keylen;
|
||||
ptr = pkey_pack_u32(ptr, pkey->algo);
|
||||
ptr = pkey_pack_u32(ptr, pkey->paramlen);
|
||||
memcpy(ptr, pkey->params, pkey->paramlen);
|
||||
|
||||
if (pkey->key_is_private)
|
||||
ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
|
||||
else
|
||||
ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
|
||||
if (ret < 0)
|
||||
goto error_free_key;
|
||||
|
||||
len = crypto_akcipher_maxsize(tfm);
|
||||
info->key_size = len * 8;
|
||||
info->max_data_size = len;
|
||||
info->max_sig_size = len;
|
||||
info->max_enc_size = len;
|
||||
info->max_dec_size = len;
|
||||
info->supported_ops = (KEYCTL_SUPPORTS_ENCRYPT |
|
||||
KEYCTL_SUPPORTS_VERIFY);
|
||||
if (pkey->key_is_private)
|
||||
info->supported_ops |= (KEYCTL_SUPPORTS_DECRYPT |
|
||||
KEYCTL_SUPPORTS_SIGN);
|
||||
ret = 0;
|
||||
|
||||
error_free_key:
|
||||
kfree(key);
|
||||
error_free_tfm:
|
||||
crypto_free_akcipher(tfm);
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do encryption, decryption and signing ops.
|
||||
*/
|
||||
static int software_key_eds_op(struct kernel_pkey_params *params,
|
||||
const void *in, void *out)
|
||||
{
|
||||
const struct public_key *pkey = params->key->payload.data[asym_crypto];
|
||||
struct akcipher_request *req;
|
||||
struct crypto_akcipher *tfm;
|
||||
struct crypto_wait cwait;
|
||||
struct scatterlist in_sg, out_sg;
|
||||
char alg_name[CRYPTO_MAX_ALG_NAME];
|
||||
char *key, *ptr;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
ret = software_key_determine_akcipher(params->encoding,
|
||||
params->hash_algo,
|
||||
pkey, alg_name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tfm = crypto_alloc_akcipher(alg_name, 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
req = akcipher_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!req)
|
||||
goto error_free_tfm;
|
||||
|
||||
key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
|
||||
GFP_KERNEL);
|
||||
if (!key)
|
||||
goto error_free_req;
|
||||
|
||||
memcpy(key, pkey->key, pkey->keylen);
|
||||
ptr = key + pkey->keylen;
|
||||
ptr = pkey_pack_u32(ptr, pkey->algo);
|
||||
ptr = pkey_pack_u32(ptr, pkey->paramlen);
|
||||
memcpy(ptr, pkey->params, pkey->paramlen);
|
||||
|
||||
if (pkey->key_is_private)
|
||||
ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
|
||||
else
|
||||
ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
|
||||
if (ret)
|
||||
goto error_free_key;
|
||||
|
||||
sg_init_one(&in_sg, in, params->in_len);
|
||||
sg_init_one(&out_sg, out, params->out_len);
|
||||
akcipher_request_set_crypt(req, &in_sg, &out_sg, params->in_len,
|
||||
params->out_len);
|
||||
crypto_init_wait(&cwait);
|
||||
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
|
||||
CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &cwait);
|
||||
|
||||
/* Perform the encryption calculation. */
|
||||
switch (params->op) {
|
||||
case kernel_pkey_encrypt:
|
||||
ret = crypto_akcipher_encrypt(req);
|
||||
break;
|
||||
case kernel_pkey_decrypt:
|
||||
ret = crypto_akcipher_decrypt(req);
|
||||
break;
|
||||
case kernel_pkey_sign:
|
||||
ret = crypto_akcipher_sign(req);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
ret = crypto_wait_req(ret, &cwait);
|
||||
if (ret == 0)
|
||||
ret = req->dst_len;
|
||||
|
||||
error_free_key:
|
||||
kfree(key);
|
||||
error_free_req:
|
||||
akcipher_request_free(req);
|
||||
error_free_tfm:
|
||||
crypto_free_akcipher(tfm);
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify a signature using a public key.
|
||||
*/
|
||||
int public_key_verify_signature(const struct public_key *pkey,
|
||||
const struct public_key_signature *sig)
|
||||
{
|
||||
struct crypto_wait cwait;
|
||||
struct crypto_akcipher *tfm;
|
||||
struct akcipher_request *req;
|
||||
struct scatterlist src_sg[2];
|
||||
char alg_name[CRYPTO_MAX_ALG_NAME];
|
||||
char *key, *ptr;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
BUG_ON(!pkey);
|
||||
BUG_ON(!sig);
|
||||
BUG_ON(!sig->s);
|
||||
|
||||
ret = software_key_determine_akcipher(sig->encoding,
|
||||
sig->hash_algo,
|
||||
pkey, alg_name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
tfm = crypto_alloc_akcipher(alg_name, 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return PTR_ERR(tfm);
|
||||
|
||||
ret = -ENOMEM;
|
||||
req = akcipher_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!req)
|
||||
goto error_free_tfm;
|
||||
|
||||
key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
|
||||
GFP_KERNEL);
|
||||
if (!key)
|
||||
goto error_free_req;
|
||||
|
||||
memcpy(key, pkey->key, pkey->keylen);
|
||||
ptr = key + pkey->keylen;
|
||||
ptr = pkey_pack_u32(ptr, pkey->algo);
|
||||
ptr = pkey_pack_u32(ptr, pkey->paramlen);
|
||||
memcpy(ptr, pkey->params, pkey->paramlen);
|
||||
|
||||
if (pkey->key_is_private)
|
||||
ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
|
||||
else
|
||||
ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
|
||||
if (ret)
|
||||
goto error_free_key;
|
||||
|
||||
sg_init_table(src_sg, 2);
|
||||
sg_set_buf(&src_sg[0], sig->s, sig->s_size);
|
||||
sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
|
||||
akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
|
||||
sig->digest_size);
|
||||
crypto_init_wait(&cwait);
|
||||
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
|
||||
CRYPTO_TFM_REQ_MAY_SLEEP,
|
||||
crypto_req_done, &cwait);
|
||||
ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
|
||||
|
||||
error_free_key:
|
||||
kfree(key);
|
||||
error_free_req:
|
||||
akcipher_request_free(req);
|
||||
error_free_tfm:
|
||||
crypto_free_akcipher(tfm);
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
if (WARN_ON_ONCE(ret > 0))
|
||||
ret = -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(public_key_verify_signature);
|
||||
|
||||
static int public_key_verify_signature_2(const struct key *key,
|
||||
const struct public_key_signature *sig)
|
||||
{
|
||||
const struct public_key *pk = key->payload.data[asym_crypto];
|
||||
return public_key_verify_signature(pk, sig);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public key algorithm asymmetric key subtype
|
||||
*/
|
||||
struct asymmetric_key_subtype public_key_subtype = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "public_key",
|
||||
.name_len = sizeof("public_key") - 1,
|
||||
.describe = public_key_describe,
|
||||
.destroy = public_key_destroy,
|
||||
.query = software_key_query,
|
||||
.eds_op = software_key_eds_op,
|
||||
.verify_signature = public_key_verify_signature_2,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(public_key_subtype);
|
||||
#endif /* !__UBOOT__ */
|
198
lib/crypto/rsa_helper.c
Normal file
198
lib/crypto/rsa_helper.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* RSA key extract helper
|
||||
*
|
||||
* Copyright (c) 2015, Intel Corporation
|
||||
* Authors: Tadeusz Struk <tadeusz.struk@intel.com>
|
||||
*/
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/export.h>
|
||||
#endif
|
||||
#include <linux/err.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/fips.h>
|
||||
#endif
|
||||
#include <crypto/internal/rsa.h>
|
||||
#include "rsapubkey.asn1.h"
|
||||
#ifndef __UBOOT__
|
||||
#include "rsaprivkey.asn1.h"
|
||||
#endif
|
||||
|
||||
int rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rsa_key *key = context;
|
||||
#ifndef __UBOOT__
|
||||
const u8 *ptr = value;
|
||||
size_t n_sz = vlen;
|
||||
#endif
|
||||
|
||||
/* invalid key provided */
|
||||
if (!value || !vlen)
|
||||
return -EINVAL;
|
||||
|
||||
#ifndef __UBOOT__
|
||||
if (fips_enabled) {
|
||||
while (n_sz && !*ptr) {
|
||||
ptr++;
|
||||
n_sz--;
|
||||
}
|
||||
|
||||
/* In FIPS mode only allow key size 2K and higher */
|
||||
if (n_sz < 256) {
|
||||
pr_err("RSA: key size not allowed in FIPS mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
key->n = value;
|
||||
key->n_sz = vlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsa_get_e(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rsa_key *key = context;
|
||||
|
||||
/* invalid key provided */
|
||||
if (!value || !key->n_sz || !vlen || vlen > key->n_sz)
|
||||
return -EINVAL;
|
||||
|
||||
key->e = value;
|
||||
key->e_sz = vlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsa_get_d(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rsa_key *key = context;
|
||||
|
||||
/* invalid key provided */
|
||||
if (!value || !key->n_sz || !vlen || vlen > key->n_sz)
|
||||
return -EINVAL;
|
||||
|
||||
key->d = value;
|
||||
key->d_sz = vlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsa_get_p(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rsa_key *key = context;
|
||||
|
||||
/* invalid key provided */
|
||||
if (!value || !vlen || vlen > key->n_sz)
|
||||
return -EINVAL;
|
||||
|
||||
key->p = value;
|
||||
key->p_sz = vlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsa_get_q(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rsa_key *key = context;
|
||||
|
||||
/* invalid key provided */
|
||||
if (!value || !vlen || vlen > key->n_sz)
|
||||
return -EINVAL;
|
||||
|
||||
key->q = value;
|
||||
key->q_sz = vlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsa_get_dp(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rsa_key *key = context;
|
||||
|
||||
/* invalid key provided */
|
||||
if (!value || !vlen || vlen > key->n_sz)
|
||||
return -EINVAL;
|
||||
|
||||
key->dp = value;
|
||||
key->dp_sz = vlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsa_get_dq(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rsa_key *key = context;
|
||||
|
||||
/* invalid key provided */
|
||||
if (!value || !vlen || vlen > key->n_sz)
|
||||
return -EINVAL;
|
||||
|
||||
key->dq = value;
|
||||
key->dq_sz = vlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rsa_get_qinv(void *context, size_t hdrlen, unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct rsa_key *key = context;
|
||||
|
||||
/* invalid key provided */
|
||||
if (!value || !vlen || vlen > key->n_sz)
|
||||
return -EINVAL;
|
||||
|
||||
key->qinv = value;
|
||||
key->qinv_sz = vlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rsa_parse_pub_key() - decodes the BER encoded buffer and stores in the
|
||||
* provided struct rsa_key, pointers to the raw key as is,
|
||||
* so that the caller can copy it or MPI parse it, etc.
|
||||
*
|
||||
* @rsa_key: struct rsa_key key representation
|
||||
* @key: key in BER format
|
||||
* @key_len: length of key
|
||||
*
|
||||
* Return: 0 on success or error code in case of error
|
||||
*/
|
||||
int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
return asn1_ber_decoder(&rsapubkey_decoder, rsa_key, key, key_len);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rsa_parse_pub_key);
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/**
|
||||
* rsa_parse_priv_key() - decodes the BER encoded buffer and stores in the
|
||||
* provided struct rsa_key, pointers to the raw key
|
||||
* as is, so that the caller can copy it or MPI parse it,
|
||||
* etc.
|
||||
*
|
||||
* @rsa_key: struct rsa_key key representation
|
||||
* @key: key in BER format
|
||||
* @key_len: length of key
|
||||
*
|
||||
* Return: 0 on success or error code in case of error
|
||||
*/
|
||||
int rsa_parse_priv_key(struct rsa_key *rsa_key, const void *key,
|
||||
unsigned int key_len)
|
||||
{
|
||||
return asn1_ber_decoder(&rsaprivkey_decoder, rsa_key, key, key_len);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rsa_parse_priv_key);
|
||||
#endif
|
4
lib/crypto/rsapubkey.asn1
Normal file
4
lib/crypto/rsapubkey.asn1
Normal file
|
@ -0,0 +1,4 @@
|
|||
RsaPubKey ::= SEQUENCE {
|
||||
n INTEGER ({ rsa_get_n }),
|
||||
e INTEGER ({ rsa_get_e })
|
||||
}
|
60
lib/crypto/x509.asn1
Normal file
60
lib/crypto/x509.asn1
Normal file
|
@ -0,0 +1,60 @@
|
|||
Certificate ::= SEQUENCE {
|
||||
tbsCertificate TBSCertificate ({ x509_note_tbs_certificate }),
|
||||
signatureAlgorithm AlgorithmIdentifier,
|
||||
signature BIT STRING ({ x509_note_signature })
|
||||
}
|
||||
|
||||
TBSCertificate ::= SEQUENCE {
|
||||
version [ 0 ] Version DEFAULT,
|
||||
serialNumber CertificateSerialNumber ({ x509_note_serial }),
|
||||
signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
|
||||
issuer Name ({ x509_note_issuer }),
|
||||
validity Validity,
|
||||
subject Name ({ x509_note_subject }),
|
||||
subjectPublicKeyInfo SubjectPublicKeyInfo,
|
||||
issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
extensions [ 3 ] Extensions OPTIONAL
|
||||
}
|
||||
|
||||
Version ::= INTEGER
|
||||
CertificateSerialNumber ::= INTEGER
|
||||
|
||||
AlgorithmIdentifier ::= SEQUENCE {
|
||||
algorithm OBJECT IDENTIFIER ({ x509_note_OID }),
|
||||
parameters ANY OPTIONAL ({ x509_note_params })
|
||||
}
|
||||
|
||||
Name ::= SEQUENCE OF RelativeDistinguishedName
|
||||
|
||||
RelativeDistinguishedName ::= SET OF AttributeValueAssertion
|
||||
|
||||
AttributeValueAssertion ::= SEQUENCE {
|
||||
attributeType OBJECT IDENTIFIER ({ x509_note_OID }),
|
||||
attributeValue ANY ({ x509_extract_name_segment })
|
||||
}
|
||||
|
||||
Validity ::= SEQUENCE {
|
||||
notBefore Time ({ x509_note_not_before }),
|
||||
notAfter Time ({ x509_note_not_after })
|
||||
}
|
||||
|
||||
Time ::= CHOICE {
|
||||
utcTime UTCTime,
|
||||
generalTime GeneralizedTime
|
||||
}
|
||||
|
||||
SubjectPublicKeyInfo ::= SEQUENCE {
|
||||
algorithm AlgorithmIdentifier,
|
||||
subjectPublicKey BIT STRING ({ x509_extract_key_data })
|
||||
}
|
||||
|
||||
UniqueIdentifier ::= BIT STRING
|
||||
|
||||
Extensions ::= SEQUENCE OF Extension
|
||||
|
||||
Extension ::= SEQUENCE {
|
||||
extnid OBJECT IDENTIFIER ({ x509_note_OID }),
|
||||
critical BOOLEAN DEFAULT,
|
||||
extnValue OCTET STRING ({ x509_process_extension })
|
||||
}
|
35
lib/crypto/x509_akid.asn1
Normal file
35
lib/crypto/x509_akid.asn1
Normal file
|
@ -0,0 +1,35 @@
|
|||
-- X.509 AuthorityKeyIdentifier
|
||||
-- rfc5280 section 4.2.1.1
|
||||
|
||||
AuthorityKeyIdentifier ::= SEQUENCE {
|
||||
keyIdentifier [0] IMPLICIT KeyIdentifier OPTIONAL,
|
||||
authorityCertIssuer [1] IMPLICIT GeneralNames OPTIONAL,
|
||||
authorityCertSerialNumber [2] IMPLICIT CertificateSerialNumber OPTIONAL
|
||||
}
|
||||
|
||||
KeyIdentifier ::= OCTET STRING ({ x509_akid_note_kid })
|
||||
|
||||
CertificateSerialNumber ::= INTEGER ({ x509_akid_note_serial })
|
||||
|
||||
GeneralNames ::= SEQUENCE OF GeneralName
|
||||
|
||||
GeneralName ::= CHOICE {
|
||||
otherName [0] ANY,
|
||||
rfc822Name [1] IA5String,
|
||||
dNSName [2] IA5String,
|
||||
x400Address [3] ANY,
|
||||
directoryName [4] Name ({ x509_akid_note_name }),
|
||||
ediPartyName [5] ANY,
|
||||
uniformResourceIdentifier [6] IA5String,
|
||||
iPAddress [7] OCTET STRING,
|
||||
registeredID [8] OBJECT IDENTIFIER
|
||||
}
|
||||
|
||||
Name ::= SEQUENCE OF RelativeDistinguishedName
|
||||
|
||||
RelativeDistinguishedName ::= SET OF AttributeValueAssertion
|
||||
|
||||
AttributeValueAssertion ::= SEQUENCE {
|
||||
attributeType OBJECT IDENTIFIER ({ x509_note_OID }),
|
||||
attributeValue ANY ({ x509_extract_name_segment })
|
||||
}
|
697
lib/crypto/x509_cert_parser.c
Normal file
697
lib/crypto/x509_cert_parser.c
Normal file
|
@ -0,0 +1,697 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* X.509 certificate parser
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "X.509: "fmt
|
||||
#include <linux/kernel.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#endif
|
||||
#include <linux/err.h>
|
||||
#include <linux/oid_registry.h>
|
||||
#ifdef __UBOOT__
|
||||
#include <linux/string.h>
|
||||
#endif
|
||||
#include <crypto/public_key.h>
|
||||
#include "x509_parser.h"
|
||||
#include "x509.asn1.h"
|
||||
#include "x509_akid.asn1.h"
|
||||
|
||||
struct x509_parse_context {
|
||||
struct x509_certificate *cert; /* Certificate being constructed */
|
||||
unsigned long data; /* Start of data */
|
||||
const void *cert_start; /* Start of cert content */
|
||||
const void *key; /* Key data */
|
||||
size_t key_size; /* Size of key data */
|
||||
const void *params; /* Key parameters */
|
||||
size_t params_size; /* Size of key parameters */
|
||||
enum OID key_algo; /* Public key algorithm */
|
||||
enum OID last_oid; /* Last OID encountered */
|
||||
enum OID algo_oid; /* Algorithm OID */
|
||||
unsigned char nr_mpi; /* Number of MPIs stored */
|
||||
u8 o_size; /* Size of organizationName (O) */
|
||||
u8 cn_size; /* Size of commonName (CN) */
|
||||
u8 email_size; /* Size of emailAddress */
|
||||
u16 o_offset; /* Offset of organizationName (O) */
|
||||
u16 cn_offset; /* Offset of commonName (CN) */
|
||||
u16 email_offset; /* Offset of emailAddress */
|
||||
unsigned raw_akid_size;
|
||||
const void *raw_akid; /* Raw authorityKeyId in ASN.1 */
|
||||
const void *akid_raw_issuer; /* Raw directoryName in authorityKeyId */
|
||||
unsigned akid_raw_issuer_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* Free an X.509 certificate
|
||||
*/
|
||||
void x509_free_certificate(struct x509_certificate *cert)
|
||||
{
|
||||
if (cert) {
|
||||
public_key_free(cert->pub);
|
||||
public_key_signature_free(cert->sig);
|
||||
kfree(cert->issuer);
|
||||
kfree(cert->subject);
|
||||
kfree(cert->id);
|
||||
kfree(cert->skid);
|
||||
kfree(cert);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(x509_free_certificate);
|
||||
|
||||
/*
|
||||
* Parse an X.509 certificate
|
||||
*/
|
||||
struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
|
||||
{
|
||||
struct x509_certificate *cert;
|
||||
struct x509_parse_context *ctx;
|
||||
struct asymmetric_key_id *kid;
|
||||
long ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
|
||||
if (!cert)
|
||||
goto error_no_cert;
|
||||
cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
|
||||
if (!cert->pub)
|
||||
goto error_no_ctx;
|
||||
cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
|
||||
if (!cert->sig)
|
||||
goto error_no_ctx;
|
||||
ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
goto error_no_ctx;
|
||||
|
||||
ctx->cert = cert;
|
||||
ctx->data = (unsigned long)data;
|
||||
|
||||
/* Attempt to decode the certificate */
|
||||
ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen);
|
||||
if (ret < 0)
|
||||
goto error_decode;
|
||||
|
||||
/* Decode the AuthorityKeyIdentifier */
|
||||
if (ctx->raw_akid) {
|
||||
pr_devel("AKID: %u %*phN\n",
|
||||
ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid);
|
||||
ret = asn1_ber_decoder(&x509_akid_decoder, ctx,
|
||||
ctx->raw_akid, ctx->raw_akid_size);
|
||||
if (ret < 0) {
|
||||
pr_warn("Couldn't decode AuthKeyIdentifier\n");
|
||||
goto error_decode;
|
||||
}
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
|
||||
if (!cert->pub->key)
|
||||
goto error_decode;
|
||||
|
||||
cert->pub->keylen = ctx->key_size;
|
||||
|
||||
cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
|
||||
if (!cert->pub->params)
|
||||
goto error_decode;
|
||||
|
||||
cert->pub->paramlen = ctx->params_size;
|
||||
cert->pub->algo = ctx->key_algo;
|
||||
|
||||
/* Grab the signature bits */
|
||||
ret = x509_get_sig_params(cert);
|
||||
if (ret < 0)
|
||||
goto error_decode;
|
||||
|
||||
/* Generate cert issuer + serial number key ID */
|
||||
kid = asymmetric_key_generate_id(cert->raw_serial,
|
||||
cert->raw_serial_size,
|
||||
cert->raw_issuer,
|
||||
cert->raw_issuer_size);
|
||||
if (IS_ERR(kid)) {
|
||||
ret = PTR_ERR(kid);
|
||||
goto error_decode;
|
||||
}
|
||||
cert->id = kid;
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/* Detect self-signed certificates */
|
||||
ret = x509_check_for_self_signed(cert);
|
||||
if (ret < 0)
|
||||
goto error_decode;
|
||||
#endif
|
||||
|
||||
kfree(ctx);
|
||||
return cert;
|
||||
|
||||
error_decode:
|
||||
kfree(ctx);
|
||||
error_no_ctx:
|
||||
x509_free_certificate(cert);
|
||||
error_no_cert:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(x509_cert_parse);
|
||||
|
||||
/*
|
||||
* Note an OID when we find one for later processing when we know how
|
||||
* to interpret it.
|
||||
*/
|
||||
int x509_note_OID(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
ctx->last_oid = look_up_OID(value, vlen);
|
||||
if (ctx->last_oid == OID__NR) {
|
||||
char buffer[50];
|
||||
sprint_oid(value, vlen, buffer, sizeof(buffer));
|
||||
pr_debug("Unknown OID: [%lu] %s\n",
|
||||
(unsigned long)value - ctx->data, buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the position of the TBS data so that we can check the signature over it
|
||||
* later.
|
||||
*/
|
||||
int x509_note_tbs_certificate(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n",
|
||||
hdrlen, tag, (unsigned long)value - ctx->data, vlen);
|
||||
|
||||
ctx->cert->tbs = value - hdrlen;
|
||||
ctx->cert->tbs_size = vlen + hdrlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record the public key algorithm
|
||||
*/
|
||||
int x509_note_pkey_algo(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
pr_debug("PubKey Algo: %u\n", ctx->last_oid);
|
||||
|
||||
switch (ctx->last_oid) {
|
||||
case OID_md2WithRSAEncryption:
|
||||
case OID_md3WithRSAEncryption:
|
||||
default:
|
||||
return -ENOPKG; /* Unsupported combination */
|
||||
|
||||
case OID_md4WithRSAEncryption:
|
||||
ctx->cert->sig->hash_algo = "md4";
|
||||
goto rsa_pkcs1;
|
||||
|
||||
case OID_sha1WithRSAEncryption:
|
||||
ctx->cert->sig->hash_algo = "sha1";
|
||||
goto rsa_pkcs1;
|
||||
|
||||
case OID_sha256WithRSAEncryption:
|
||||
ctx->cert->sig->hash_algo = "sha256";
|
||||
goto rsa_pkcs1;
|
||||
|
||||
case OID_sha384WithRSAEncryption:
|
||||
ctx->cert->sig->hash_algo = "sha384";
|
||||
goto rsa_pkcs1;
|
||||
|
||||
case OID_sha512WithRSAEncryption:
|
||||
ctx->cert->sig->hash_algo = "sha512";
|
||||
goto rsa_pkcs1;
|
||||
|
||||
case OID_sha224WithRSAEncryption:
|
||||
ctx->cert->sig->hash_algo = "sha224";
|
||||
goto rsa_pkcs1;
|
||||
|
||||
case OID_gost2012Signature256:
|
||||
ctx->cert->sig->hash_algo = "streebog256";
|
||||
goto ecrdsa;
|
||||
|
||||
case OID_gost2012Signature512:
|
||||
ctx->cert->sig->hash_algo = "streebog512";
|
||||
goto ecrdsa;
|
||||
}
|
||||
|
||||
rsa_pkcs1:
|
||||
ctx->cert->sig->pkey_algo = "rsa";
|
||||
ctx->cert->sig->encoding = "pkcs1";
|
||||
ctx->algo_oid = ctx->last_oid;
|
||||
return 0;
|
||||
ecrdsa:
|
||||
ctx->cert->sig->pkey_algo = "ecrdsa";
|
||||
ctx->cert->sig->encoding = "raw";
|
||||
ctx->algo_oid = ctx->last_oid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the whereabouts and type of the signature.
|
||||
*/
|
||||
int x509_note_signature(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen);
|
||||
|
||||
if (ctx->last_oid != ctx->algo_oid) {
|
||||
pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n",
|
||||
ctx->algo_oid, ctx->last_oid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
|
||||
strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0) {
|
||||
/* Discard the BIT STRING metadata */
|
||||
if (vlen < 1 || *(const u8 *)value != 0)
|
||||
return -EBADMSG;
|
||||
|
||||
value++;
|
||||
vlen--;
|
||||
}
|
||||
|
||||
ctx->cert->raw_sig = value;
|
||||
ctx->cert->raw_sig_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the certificate serial number
|
||||
*/
|
||||
int x509_note_serial(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
ctx->cert->raw_serial = value;
|
||||
ctx->cert->raw_serial_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note some of the name segments from which we'll fabricate a name.
|
||||
*/
|
||||
int x509_extract_name_segment(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
switch (ctx->last_oid) {
|
||||
case OID_commonName:
|
||||
ctx->cn_size = vlen;
|
||||
ctx->cn_offset = (unsigned long)value - ctx->data;
|
||||
break;
|
||||
case OID_organizationName:
|
||||
ctx->o_size = vlen;
|
||||
ctx->o_offset = (unsigned long)value - ctx->data;
|
||||
break;
|
||||
case OID_email_address:
|
||||
ctx->email_size = vlen;
|
||||
ctx->email_offset = (unsigned long)value - ctx->data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fabricate and save the issuer and subject names
|
||||
*/
|
||||
static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
char **_name, size_t vlen)
|
||||
{
|
||||
const void *name, *data = (const void *)ctx->data;
|
||||
size_t namesize;
|
||||
char *buffer;
|
||||
|
||||
if (*_name)
|
||||
return -EINVAL;
|
||||
|
||||
/* Empty name string if no material */
|
||||
if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) {
|
||||
buffer = kmalloc(1, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
buffer[0] = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ctx->cn_size && ctx->o_size) {
|
||||
/* Consider combining O and CN, but use only the CN if it is
|
||||
* prefixed by the O, or a significant portion thereof.
|
||||
*/
|
||||
namesize = ctx->cn_size;
|
||||
name = data + ctx->cn_offset;
|
||||
if (ctx->cn_size >= ctx->o_size &&
|
||||
memcmp(data + ctx->cn_offset, data + ctx->o_offset,
|
||||
ctx->o_size) == 0)
|
||||
goto single_component;
|
||||
if (ctx->cn_size >= 7 &&
|
||||
ctx->o_size >= 7 &&
|
||||
memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0)
|
||||
goto single_component;
|
||||
|
||||
buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1,
|
||||
GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buffer,
|
||||
data + ctx->o_offset, ctx->o_size);
|
||||
buffer[ctx->o_size + 0] = ':';
|
||||
buffer[ctx->o_size + 1] = ' ';
|
||||
memcpy(buffer + ctx->o_size + 2,
|
||||
data + ctx->cn_offset, ctx->cn_size);
|
||||
buffer[ctx->o_size + 2 + ctx->cn_size] = 0;
|
||||
goto done;
|
||||
|
||||
} else if (ctx->cn_size) {
|
||||
namesize = ctx->cn_size;
|
||||
name = data + ctx->cn_offset;
|
||||
} else if (ctx->o_size) {
|
||||
namesize = ctx->o_size;
|
||||
name = data + ctx->o_offset;
|
||||
} else {
|
||||
namesize = ctx->email_size;
|
||||
name = data + ctx->email_offset;
|
||||
}
|
||||
|
||||
single_component:
|
||||
buffer = kmalloc(namesize + 1, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
memcpy(buffer, name, namesize);
|
||||
buffer[namesize] = 0;
|
||||
|
||||
done:
|
||||
*_name = buffer;
|
||||
ctx->cn_size = 0;
|
||||
ctx->o_size = 0;
|
||||
ctx->email_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int x509_note_issuer(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
ctx->cert->raw_issuer = value;
|
||||
ctx->cert->raw_issuer_size = vlen;
|
||||
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
|
||||
}
|
||||
|
||||
int x509_note_subject(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
ctx->cert->raw_subject = value;
|
||||
ctx->cert->raw_subject_size = vlen;
|
||||
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the parameters for the public key
|
||||
*/
|
||||
int x509_note_params(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
/*
|
||||
* AlgorithmIdentifier is used three times in the x509, we should skip
|
||||
* first and ignore third, using second one which is after subject and
|
||||
* before subjectPublicKey.
|
||||
*/
|
||||
if (!ctx->cert->raw_subject || ctx->key)
|
||||
return 0;
|
||||
ctx->params = value - hdrlen;
|
||||
ctx->params_size = vlen + hdrlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the data for the public key algorithm
|
||||
*/
|
||||
int x509_extract_key_data(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
ctx->key_algo = ctx->last_oid;
|
||||
if (ctx->last_oid == OID_rsaEncryption)
|
||||
ctx->cert->pub->pkey_algo = "rsa";
|
||||
else if (ctx->last_oid == OID_gost2012PKey256 ||
|
||||
ctx->last_oid == OID_gost2012PKey512)
|
||||
ctx->cert->pub->pkey_algo = "ecrdsa";
|
||||
else
|
||||
return -ENOPKG;
|
||||
|
||||
/* Discard the BIT STRING metadata */
|
||||
if (vlen < 1 || *(const u8 *)value != 0)
|
||||
return -EBADMSG;
|
||||
ctx->key = value + 1;
|
||||
ctx->key_size = vlen - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */
|
||||
#define SEQ_TAG_KEYID (ASN1_CONT << 6)
|
||||
|
||||
/*
|
||||
* Process certificate extensions that are used to qualify the certificate.
|
||||
*/
|
||||
int x509_process_extension(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
struct asymmetric_key_id *kid;
|
||||
const unsigned char *v = value;
|
||||
|
||||
pr_debug("Extension: %u\n", ctx->last_oid);
|
||||
|
||||
if (ctx->last_oid == OID_subjectKeyIdentifier) {
|
||||
/* Get hold of the key fingerprint */
|
||||
if (ctx->cert->skid || vlen < 3)
|
||||
return -EBADMSG;
|
||||
if (v[0] != ASN1_OTS || v[1] != vlen - 2)
|
||||
return -EBADMSG;
|
||||
v += 2;
|
||||
vlen -= 2;
|
||||
|
||||
ctx->cert->raw_skid_size = vlen;
|
||||
ctx->cert->raw_skid = v;
|
||||
kid = asymmetric_key_generate_id(v, vlen, "", 0);
|
||||
if (IS_ERR(kid))
|
||||
return PTR_ERR(kid);
|
||||
ctx->cert->skid = kid;
|
||||
pr_debug("subjkeyid %*phN\n", kid->len, kid->data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->last_oid == OID_authorityKeyIdentifier) {
|
||||
/* Get hold of the CA key fingerprint */
|
||||
ctx->raw_akid = v;
|
||||
ctx->raw_akid_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* x509_decode_time - Decode an X.509 time ASN.1 object
|
||||
* @_t: The time to fill in
|
||||
* @hdrlen: The length of the object header
|
||||
* @tag: The object tag
|
||||
* @value: The object value
|
||||
* @vlen: The size of the object value
|
||||
*
|
||||
* Decode an ASN.1 universal time or generalised time field into a struct the
|
||||
* kernel can handle and check it for validity. The time is decoded thus:
|
||||
*
|
||||
* [RFC5280 §4.1.2.5]
|
||||
* CAs conforming to this profile MUST always encode certificate validity
|
||||
* dates through the year 2049 as UTCTime; certificate validity dates in
|
||||
* 2050 or later MUST be encoded as GeneralizedTime. Conforming
|
||||
* applications MUST be able to process validity dates that are encoded in
|
||||
* either UTCTime or GeneralizedTime.
|
||||
*/
|
||||
int x509_decode_time(time64_t *_t, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const unsigned char *value, size_t vlen)
|
||||
{
|
||||
static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
|
||||
31, 31, 30, 31, 30, 31 };
|
||||
const unsigned char *p = value;
|
||||
unsigned year, mon, day, hour, min, sec, mon_len;
|
||||
|
||||
#define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; })
|
||||
#define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
|
||||
|
||||
if (tag == ASN1_UNITIM) {
|
||||
/* UTCTime: YYMMDDHHMMSSZ */
|
||||
if (vlen != 13)
|
||||
goto unsupported_time;
|
||||
year = DD2bin(p);
|
||||
if (year >= 50)
|
||||
year += 1900;
|
||||
else
|
||||
year += 2000;
|
||||
} else if (tag == ASN1_GENTIM) {
|
||||
/* GenTime: YYYYMMDDHHMMSSZ */
|
||||
if (vlen != 15)
|
||||
goto unsupported_time;
|
||||
year = DD2bin(p) * 100 + DD2bin(p);
|
||||
if (year >= 1950 && year <= 2049)
|
||||
goto invalid_time;
|
||||
} else {
|
||||
goto unsupported_time;
|
||||
}
|
||||
|
||||
mon = DD2bin(p);
|
||||
day = DD2bin(p);
|
||||
hour = DD2bin(p);
|
||||
min = DD2bin(p);
|
||||
sec = DD2bin(p);
|
||||
|
||||
if (*p != 'Z')
|
||||
goto unsupported_time;
|
||||
|
||||
if (year < 1970 ||
|
||||
mon < 1 || mon > 12)
|
||||
goto invalid_time;
|
||||
|
||||
mon_len = month_lengths[mon - 1];
|
||||
if (mon == 2) {
|
||||
if (year % 4 == 0) {
|
||||
mon_len = 29;
|
||||
if (year % 100 == 0) {
|
||||
mon_len = 28;
|
||||
if (year % 400 == 0)
|
||||
mon_len = 29;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (day < 1 || day > mon_len ||
|
||||
hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */
|
||||
min > 59 ||
|
||||
sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */
|
||||
goto invalid_time;
|
||||
|
||||
*_t = mktime64(year, mon, day, hour, min, sec);
|
||||
return 0;
|
||||
|
||||
unsupported_time:
|
||||
pr_debug("Got unsupported time [tag %02x]: '%*phN'\n",
|
||||
tag, (int)vlen, value);
|
||||
return -EBADMSG;
|
||||
invalid_time:
|
||||
pr_debug("Got invalid time [tag %02x]: '%*phN'\n",
|
||||
tag, (int)vlen, value);
|
||||
return -EBADMSG;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(x509_decode_time);
|
||||
|
||||
int x509_note_not_before(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
|
||||
}
|
||||
|
||||
int x509_note_not_after(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note a key identifier-based AuthorityKeyIdentifier
|
||||
*/
|
||||
int x509_akid_note_kid(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
struct asymmetric_key_id *kid;
|
||||
|
||||
pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
|
||||
|
||||
if (ctx->cert->sig->auth_ids[1])
|
||||
return 0;
|
||||
|
||||
kid = asymmetric_key_generate_id(value, vlen, "", 0);
|
||||
if (IS_ERR(kid))
|
||||
return PTR_ERR(kid);
|
||||
pr_debug("authkeyid %*phN\n", kid->len, kid->data);
|
||||
ctx->cert->sig->auth_ids[1] = kid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note a directoryName in an AuthorityKeyIdentifier
|
||||
*/
|
||||
int x509_akid_note_name(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
pr_debug("AKID: name: %*phN\n", (int)vlen, value);
|
||||
|
||||
ctx->akid_raw_issuer = value;
|
||||
ctx->akid_raw_issuer_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note a serial number in an AuthorityKeyIdentifier
|
||||
*/
|
||||
int x509_akid_note_serial(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
struct asymmetric_key_id *kid;
|
||||
|
||||
pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
|
||||
|
||||
if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
|
||||
return 0;
|
||||
|
||||
kid = asymmetric_key_generate_id(value,
|
||||
vlen,
|
||||
ctx->akid_raw_issuer,
|
||||
ctx->akid_raw_issuer_size);
|
||||
if (IS_ERR(kid))
|
||||
return PTR_ERR(kid);
|
||||
|
||||
pr_debug("authkeyid %*phN\n", kid->len, kid->data);
|
||||
ctx->cert->sig->auth_ids[0] = kid;
|
||||
return 0;
|
||||
}
|
57
lib/crypto/x509_parser.h
Normal file
57
lib/crypto/x509_parser.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/* X.509 certificate parser internal definitions
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <crypto/public_key.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
|
||||
struct x509_certificate {
|
||||
struct x509_certificate *next;
|
||||
struct x509_certificate *signer; /* Certificate that signed this one */
|
||||
struct public_key *pub; /* Public key details */
|
||||
struct public_key_signature *sig; /* Signature parameters */
|
||||
char *issuer; /* Name of certificate issuer */
|
||||
char *subject; /* Name of certificate subject */
|
||||
struct asymmetric_key_id *id; /* Issuer + Serial number */
|
||||
struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */
|
||||
time64_t valid_from;
|
||||
time64_t valid_to;
|
||||
const void *tbs; /* Signed data */
|
||||
unsigned tbs_size; /* Size of signed data */
|
||||
unsigned raw_sig_size; /* Size of sigature */
|
||||
const void *raw_sig; /* Signature data */
|
||||
const void *raw_serial; /* Raw serial number in ASN.1 */
|
||||
unsigned raw_serial_size;
|
||||
unsigned raw_issuer_size;
|
||||
const void *raw_issuer; /* Raw issuer name in ASN.1 */
|
||||
const void *raw_subject; /* Raw subject name in ASN.1 */
|
||||
unsigned raw_subject_size;
|
||||
unsigned raw_skid_size;
|
||||
const void *raw_skid; /* Raw subjectKeyId in ASN.1 */
|
||||
unsigned index;
|
||||
bool seen; /* Infinite recursion prevention */
|
||||
bool verified;
|
||||
bool self_signed; /* T if self-signed (check unsupported_sig too) */
|
||||
bool unsupported_key; /* T if key uses unsupported crypto */
|
||||
bool unsupported_sig; /* T if signature uses unsupported crypto */
|
||||
bool blacklisted;
|
||||
};
|
||||
|
||||
/*
|
||||
* x509_cert_parser.c
|
||||
*/
|
||||
extern void x509_free_certificate(struct x509_certificate *cert);
|
||||
extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
|
||||
extern int x509_decode_time(time64_t *_t, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const unsigned char *value, size_t vlen);
|
||||
|
||||
/*
|
||||
* x509_public_key.c
|
||||
*/
|
||||
extern int x509_get_sig_params(struct x509_certificate *cert);
|
||||
extern int x509_check_for_self_signed(struct x509_certificate *cert);
|
292
lib/crypto/x509_public_key.c
Normal file
292
lib/crypto/x509_public_key.c
Normal file
|
@ -0,0 +1,292 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Instantiate a public key crypto key from an X.509 Certificate
|
||||
*
|
||||
* Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "X.509: "fmt
|
||||
#ifdef __UBOOT__
|
||||
#include <common.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/errno.h>
|
||||
#else
|
||||
#include <linux/module.h>
|
||||
#endif
|
||||
#include <linux/kernel.h>
|
||||
#ifndef __UBOOT__
|
||||
#include <linux/slab.h>
|
||||
#include <keys/asymmetric-subtype.h>
|
||||
#include <keys/asymmetric-parser.h>
|
||||
#include <keys/system_keyring.h>
|
||||
#include <crypto/hash.h>
|
||||
#include "asymmetric_keys.h"
|
||||
#endif
|
||||
#include "x509_parser.h"
|
||||
|
||||
/*
|
||||
* Set up the signature parameters in an X.509 certificate. This involves
|
||||
* digesting the signed data and extracting the signature.
|
||||
*/
|
||||
int x509_get_sig_params(struct x509_certificate *cert)
|
||||
{
|
||||
struct public_key_signature *sig = cert->sig;
|
||||
#ifndef __UBOOT__
|
||||
struct crypto_shash *tfm;
|
||||
struct shash_desc *desc;
|
||||
size_t desc_size;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
if (!cert->pub->pkey_algo)
|
||||
cert->unsupported_key = true;
|
||||
|
||||
if (!sig->pkey_algo)
|
||||
cert->unsupported_sig = true;
|
||||
|
||||
/* We check the hash if we can - even if we can't then verify it */
|
||||
if (!sig->hash_algo) {
|
||||
cert->unsupported_sig = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL);
|
||||
if (!sig->s)
|
||||
return -ENOMEM;
|
||||
|
||||
sig->s_size = cert->raw_sig_size;
|
||||
|
||||
#ifdef __UBOOT__
|
||||
/*
|
||||
* Note:
|
||||
* This part (filling sig->digest) should be implemented if
|
||||
* x509_check_for_self_signed() is enabled x509_cert_parse().
|
||||
* Currently, this check won't affect UEFI secure boot.
|
||||
*/
|
||||
ret = 0;
|
||||
#else
|
||||
/* Allocate the hashing algorithm we're going to need and find out how
|
||||
* big the hash operational data will be.
|
||||
*/
|
||||
tfm = crypto_alloc_shash(sig->hash_algo, 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
if (PTR_ERR(tfm) == -ENOENT) {
|
||||
cert->unsupported_sig = true;
|
||||
return 0;
|
||||
}
|
||||
return PTR_ERR(tfm);
|
||||
}
|
||||
|
||||
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
|
||||
sig->digest_size = crypto_shash_digestsize(tfm);
|
||||
|
||||
ret = -ENOMEM;
|
||||
sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
|
||||
if (!sig->digest)
|
||||
goto error;
|
||||
|
||||
desc = kzalloc(desc_size, GFP_KERNEL);
|
||||
if (!desc)
|
||||
goto error;
|
||||
|
||||
desc->tfm = tfm;
|
||||
|
||||
ret = crypto_shash_digest(desc, cert->tbs, cert->tbs_size, sig->digest);
|
||||
if (ret < 0)
|
||||
goto error_2;
|
||||
|
||||
ret = is_hash_blacklisted(sig->digest, sig->digest_size, "tbs");
|
||||
if (ret == -EKEYREJECTED) {
|
||||
pr_err("Cert %*phN is blacklisted\n",
|
||||
sig->digest_size, sig->digest);
|
||||
cert->blacklisted = true;
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
error_2:
|
||||
kfree(desc);
|
||||
error:
|
||||
crypto_free_shash(tfm);
|
||||
#endif /* __UBOOT__ */
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef __UBOOT__
|
||||
/*
|
||||
* Check for self-signedness in an X.509 cert and if found, check the signature
|
||||
* immediately if we can.
|
||||
*/
|
||||
int x509_check_for_self_signed(struct x509_certificate *cert)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
if (cert->raw_subject_size != cert->raw_issuer_size ||
|
||||
memcmp(cert->raw_subject, cert->raw_issuer,
|
||||
cert->raw_issuer_size) != 0)
|
||||
goto not_self_signed;
|
||||
|
||||
if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) {
|
||||
/* If the AKID is present it may have one or two parts. If
|
||||
* both are supplied, both must match.
|
||||
*/
|
||||
bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]);
|
||||
bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]);
|
||||
|
||||
if (!a && !b)
|
||||
goto not_self_signed;
|
||||
|
||||
ret = -EKEYREJECTED;
|
||||
if (((a && !b) || (b && !a)) &&
|
||||
cert->sig->auth_ids[0] && cert->sig->auth_ids[1])
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = -EKEYREJECTED;
|
||||
if (strcmp(cert->pub->pkey_algo, cert->sig->pkey_algo) != 0)
|
||||
goto out;
|
||||
|
||||
ret = public_key_verify_signature(cert->pub, cert->sig);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENOPKG) {
|
||||
cert->unsupported_sig = true;
|
||||
ret = 0;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_devel("Cert Self-signature verified");
|
||||
cert->self_signed = true;
|
||||
|
||||
out:
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
|
||||
not_self_signed:
|
||||
pr_devel("<==%s() = 0 [not]\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to parse a data blob for a key as an X509 certificate.
|
||||
*/
|
||||
static int x509_key_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct asymmetric_key_ids *kids;
|
||||
struct x509_certificate *cert;
|
||||
const char *q;
|
||||
size_t srlen, sulen;
|
||||
char *desc = NULL, *p;
|
||||
int ret;
|
||||
|
||||
cert = x509_cert_parse(prep->data, prep->datalen);
|
||||
if (IS_ERR(cert))
|
||||
return PTR_ERR(cert);
|
||||
|
||||
pr_devel("Cert Issuer: %s\n", cert->issuer);
|
||||
pr_devel("Cert Subject: %s\n", cert->subject);
|
||||
|
||||
if (cert->unsupported_key) {
|
||||
ret = -ENOPKG;
|
||||
goto error_free_cert;
|
||||
}
|
||||
|
||||
pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo);
|
||||
pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
|
||||
|
||||
cert->pub->id_type = "X509";
|
||||
|
||||
if (cert->unsupported_sig) {
|
||||
public_key_signature_free(cert->sig);
|
||||
cert->sig = NULL;
|
||||
} else {
|
||||
pr_devel("Cert Signature: %s + %s\n",
|
||||
cert->sig->pkey_algo, cert->sig->hash_algo);
|
||||
}
|
||||
|
||||
/* Don't permit addition of blacklisted keys */
|
||||
ret = -EKEYREJECTED;
|
||||
if (cert->blacklisted)
|
||||
goto error_free_cert;
|
||||
|
||||
/* Propose a description */
|
||||
sulen = strlen(cert->subject);
|
||||
if (cert->raw_skid) {
|
||||
srlen = cert->raw_skid_size;
|
||||
q = cert->raw_skid;
|
||||
} else {
|
||||
srlen = cert->raw_serial_size;
|
||||
q = cert->raw_serial;
|
||||
}
|
||||
|
||||
ret = -ENOMEM;
|
||||
desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
|
||||
if (!desc)
|
||||
goto error_free_cert;
|
||||
p = memcpy(desc, cert->subject, sulen);
|
||||
p += sulen;
|
||||
*p++ = ':';
|
||||
*p++ = ' ';
|
||||
p = bin2hex(p, q, srlen);
|
||||
*p = 0;
|
||||
|
||||
kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
|
||||
if (!kids)
|
||||
goto error_free_desc;
|
||||
kids->id[0] = cert->id;
|
||||
kids->id[1] = cert->skid;
|
||||
|
||||
/* We're pinning the module by being linked against it */
|
||||
__module_get(public_key_subtype.owner);
|
||||
prep->payload.data[asym_subtype] = &public_key_subtype;
|
||||
prep->payload.data[asym_key_ids] = kids;
|
||||
prep->payload.data[asym_crypto] = cert->pub;
|
||||
prep->payload.data[asym_auth] = cert->sig;
|
||||
prep->description = desc;
|
||||
prep->quotalen = 100;
|
||||
|
||||
/* We've finished with the certificate */
|
||||
cert->pub = NULL;
|
||||
cert->id = NULL;
|
||||
cert->skid = NULL;
|
||||
cert->sig = NULL;
|
||||
desc = NULL;
|
||||
ret = 0;
|
||||
|
||||
error_free_desc:
|
||||
kfree(desc);
|
||||
error_free_cert:
|
||||
x509_free_certificate(cert);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct asymmetric_key_parser x509_key_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "x509",
|
||||
.parse = x509_key_preparse,
|
||||
};
|
||||
|
||||
/*
|
||||
* Module stuff
|
||||
*/
|
||||
static int __init x509_key_init(void)
|
||||
{
|
||||
return register_asymmetric_key_parser(&x509_key_parser);
|
||||
}
|
||||
|
||||
static void __exit x509_key_exit(void)
|
||||
{
|
||||
unregister_asymmetric_key_parser(&x509_key_parser);
|
||||
}
|
||||
|
||||
module_init(x509_key_init);
|
||||
module_exit(x509_key_exit);
|
||||
#endif /* !__UBOOT__ */
|
||||
|
||||
MODULE_DESCRIPTION("X.509 certificate parser");
|
||||
MODULE_AUTHOR("Red Hat, Inc.");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -8,9 +8,9 @@
|
|||
#include <command.h>
|
||||
#include <errno.h>
|
||||
#include <rtc.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#if defined(CONFIG_CMD_DATE) || defined(CONFIG_DM_RTC) || \
|
||||
defined(CONFIG_TIMESTAMP)
|
||||
#if defined(CONFIG_LIB_DATE) || defined(CONFIG_TIMESTAMP)
|
||||
|
||||
#define FEBRUARY 2
|
||||
#define STARTOFTIME 1970
|
||||
|
@ -97,4 +97,23 @@ unsigned long rtc_mktime(const struct rtc_time *tm)
|
|||
return (hours * 60 + tm->tm_min) * 60 + tm->tm_sec;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_LIB_DATE || CONFIG_TIMESTAMP */
|
||||
|
||||
#ifdef CONFIG_LIB_DATE
|
||||
/* for compatibility with linux code */
|
||||
time64_t mktime64(const unsigned int year, const unsigned int mon,
|
||||
const unsigned int day, const unsigned int hour,
|
||||
const unsigned int min, const unsigned int sec)
|
||||
{
|
||||
struct rtc_time time;
|
||||
|
||||
time.tm_year = year;
|
||||
time.tm_mon = mon;
|
||||
time.tm_mday = day;
|
||||
time.tm_hour = hour;
|
||||
time.tm_min = min;
|
||||
time.tm_sec = sec;
|
||||
|
||||
return (time64_t)rtc_mktime((const struct rtc_time *)&time);
|
||||
}
|
||||
#endif
|
|
@ -40,3 +40,22 @@ void *kmem_cache_alloc(struct kmem_cache *obj, int flag)
|
|||
{
|
||||
return malloc_cache_aligned(obj->sz);
|
||||
}
|
||||
|
||||
/**
|
||||
* kmemdup - duplicate region of memory
|
||||
*
|
||||
* @src: memory region to duplicate
|
||||
* @len: memory region length
|
||||
* @gfp: GFP mask to use
|
||||
*
|
||||
* Return: newly allocated copy of @src or %NULL in case of error
|
||||
*/
|
||||
void *kmemdup(const void *src, size_t len, gfp_t gfp)
|
||||
{
|
||||
void *p;
|
||||
|
||||
p = kmalloc(len, gfp);
|
||||
if (p)
|
||||
memcpy(p, src, len);
|
||||
return p;
|
||||
}
|
||||
|
|
179
lib/oid_registry.c
Normal file
179
lib/oid_registry.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
// 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)
|
||||
*/
|
||||
|
||||
#ifdef __UBOOT__
|
||||
#include <linux/compat.h>
|
||||
#else
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#endif
|
||||
#include <linux/oid_registry.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/bug.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);
|
||||
|
||||
/*
|
||||
* 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);
|
|
@ -328,10 +328,10 @@ $(obj)/%.lds: $(src)/%.lds.S FORCE
|
|||
# ASN.1 grammar
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_asn1_compiler = ASN.1 $@
|
||||
cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \
|
||||
cmd_asn1_compiler = $(objtree)/tools/asn1_compiler $< \
|
||||
$(subst .h,.c,$@) $(subst .c,.h,$@)
|
||||
|
||||
$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler
|
||||
$(obj)/%.asn1.c $(obj)/%.asn1.h: $(src)/%.asn1 $(objtree)/tools/asn1_compiler
|
||||
$(call cmd,asn1_compiler)
|
||||
|
||||
# Build the compiled-in targets
|
||||
|
|
203
scripts/build_OID_registry
Executable file
203
scripts/build_OID_registry
Executable file
|
@ -0,0 +1,203 @@
|
|||
#!/usr/bin/perl -w
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#
|
||||
# Build a static ASN.1 Object Identified (OID) registry
|
||||
#
|
||||
# Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
|
||||
# Written by David Howells (dhowells@redhat.com)
|
||||
#
|
||||
|
||||
use strict;
|
||||
|
||||
my @names = ();
|
||||
my @oids = ();
|
||||
|
||||
if ($#ARGV != 1) {
|
||||
print STDERR "Format: ", $0, " <in-h-file> <out-c-file>\n";
|
||||
exit(2);
|
||||
}
|
||||
|
||||
#
|
||||
# Open the file to read from
|
||||
#
|
||||
open IN_FILE, "<$ARGV[0]" || die;
|
||||
while (<IN_FILE>) {
|
||||
chomp;
|
||||
if (m!\s+OID_([a-zA-z][a-zA-Z0-9_]+),\s+/[*]\s+([012][.0-9]*)\s+[*]/!) {
|
||||
push @names, $1;
|
||||
push @oids, $2;
|
||||
}
|
||||
}
|
||||
close IN_FILE || die;
|
||||
|
||||
#
|
||||
# Open the files to write into
|
||||
#
|
||||
open C_FILE, ">$ARGV[1]" or die;
|
||||
print C_FILE "/*\n";
|
||||
print C_FILE " * Automatically generated by ", $0, ". Do not edit\n";
|
||||
print C_FILE " */\n";
|
||||
|
||||
#
|
||||
# Split the data up into separate lists and also determine the lengths of the
|
||||
# encoded data arrays.
|
||||
#
|
||||
my @indices = ();
|
||||
my @lengths = ();
|
||||
my $total_length = 0;
|
||||
|
||||
for (my $i = 0; $i <= $#names; $i++) {
|
||||
my $name = $names[$i];
|
||||
my $oid = $oids[$i];
|
||||
|
||||
my @components = split(/[.]/, $oid);
|
||||
|
||||
# Determine the encoded length of this OID
|
||||
my $size = $#components;
|
||||
for (my $loop = 2; $loop <= $#components; $loop++) {
|
||||
my $c = $components[$loop];
|
||||
|
||||
# We will base128 encode the number
|
||||
my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
|
||||
$tmp = int($tmp / 7);
|
||||
$size += $tmp;
|
||||
}
|
||||
push @lengths, $size;
|
||||
push @indices, $total_length;
|
||||
$total_length += $size;
|
||||
}
|
||||
|
||||
#
|
||||
# Emit the look-up-by-OID index table
|
||||
#
|
||||
print C_FILE "\n";
|
||||
if ($total_length <= 255) {
|
||||
print C_FILE "static const unsigned char oid_index[OID__NR + 1] = {\n";
|
||||
} else {
|
||||
print C_FILE "static const unsigned short oid_index[OID__NR + 1] = {\n";
|
||||
}
|
||||
for (my $i = 0; $i <= $#names; $i++) {
|
||||
print C_FILE "\t[OID_", $names[$i], "] = ", $indices[$i], ",\n"
|
||||
}
|
||||
print C_FILE "\t[OID__NR] = ", $total_length, "\n";
|
||||
print C_FILE "};\n";
|
||||
|
||||
#
|
||||
# Encode the OIDs
|
||||
#
|
||||
my @encoded_oids = ();
|
||||
|
||||
for (my $i = 0; $i <= $#names; $i++) {
|
||||
my @octets = ();
|
||||
|
||||
my @components = split(/[.]/, $oids[$i]);
|
||||
|
||||
push @octets, $components[0] * 40 + $components[1];
|
||||
|
||||
for (my $loop = 2; $loop <= $#components; $loop++) {
|
||||
my $c = $components[$loop];
|
||||
|
||||
# Base128 encode the number
|
||||
my $tmp = ($c == 0) ? 0 : int(log($c)/log(2));
|
||||
$tmp = int($tmp / 7);
|
||||
|
||||
for (; $tmp > 0; $tmp--) {
|
||||
push @octets, (($c >> $tmp * 7) & 0x7f) | 0x80;
|
||||
}
|
||||
push @octets, $c & 0x7f;
|
||||
}
|
||||
|
||||
push @encoded_oids, \@octets;
|
||||
}
|
||||
|
||||
#
|
||||
# Create a hash value for each OID
|
||||
#
|
||||
my @hash_values = ();
|
||||
for (my $i = 0; $i <= $#names; $i++) {
|
||||
my @octets = @{$encoded_oids[$i]};
|
||||
|
||||
my $hash = $#octets;
|
||||
foreach (@octets) {
|
||||
$hash += $_ * 33;
|
||||
}
|
||||
|
||||
$hash = ($hash >> 24) ^ ($hash >> 16) ^ ($hash >> 8) ^ ($hash);
|
||||
|
||||
push @hash_values, $hash & 0xff;
|
||||
}
|
||||
|
||||
#
|
||||
# Emit the OID data
|
||||
#
|
||||
print C_FILE "\n";
|
||||
print C_FILE "static const unsigned char oid_data[", $total_length, "] = {\n";
|
||||
for (my $i = 0; $i <= $#names; $i++) {
|
||||
my @octets = @{$encoded_oids[$i]};
|
||||
print C_FILE "\t";
|
||||
print C_FILE $_, ", " foreach (@octets);
|
||||
print C_FILE "\t// ", $names[$i];
|
||||
print C_FILE "\n";
|
||||
}
|
||||
print C_FILE "};\n";
|
||||
|
||||
#
|
||||
# Build the search index table (ordered by length then hash then content)
|
||||
#
|
||||
my @index_table = ( 0 .. $#names );
|
||||
|
||||
@index_table = sort {
|
||||
my @octets_a = @{$encoded_oids[$a]};
|
||||
my @octets_b = @{$encoded_oids[$b]};
|
||||
|
||||
return $hash_values[$a] <=> $hash_values[$b]
|
||||
if ($hash_values[$a] != $hash_values[$b]);
|
||||
return $#octets_a <=> $#octets_b
|
||||
if ($#octets_a != $#octets_b);
|
||||
for (my $i = $#octets_a; $i >= 0; $i--) {
|
||||
return $octets_a[$i] <=> $octets_b[$i]
|
||||
if ($octets_a[$i] != $octets_b[$i]);
|
||||
}
|
||||
return 0;
|
||||
|
||||
} @index_table;
|
||||
|
||||
#
|
||||
# Emit the search index and hash value table
|
||||
#
|
||||
print C_FILE "\n";
|
||||
print C_FILE "static const struct {\n";
|
||||
print C_FILE "\tunsigned char hash;\n";
|
||||
if ($#names <= 255) {
|
||||
print C_FILE "\tenum OID oid : 8;\n";
|
||||
} else {
|
||||
print C_FILE "\tenum OID oid : 16;\n";
|
||||
}
|
||||
print C_FILE "} oid_search_table[OID__NR] = {\n";
|
||||
for (my $i = 0; $i <= $#names; $i++) {
|
||||
my @octets = @{$encoded_oids[$index_table[$i]]};
|
||||
printf(C_FILE "\t[%3u] = { %3u, OID_%-35s }, // ",
|
||||
$i,
|
||||
$hash_values[$index_table[$i]],
|
||||
$names[$index_table[$i]]);
|
||||
printf C_FILE "%02x", $_ foreach (@octets);
|
||||
print C_FILE "\n";
|
||||
}
|
||||
print C_FILE "};\n";
|
||||
|
||||
#
|
||||
# Emit the OID debugging name table
|
||||
#
|
||||
#print C_FILE "\n";
|
||||
#print C_FILE "const char *const oid_name_table[OID__NR + 1] = {\n";
|
||||
#
|
||||
#for (my $i = 0; $i <= $#names; $i++) {
|
||||
# print C_FILE "\t\"", $names[$i], "\",\n"
|
||||
#}
|
||||
#print C_FILE "\t\"Unknown-OID\"\n";
|
||||
#print C_FILE "};\n";
|
||||
|
||||
#
|
||||
# Polish off
|
||||
#
|
||||
close C_FILE or die;
|
18
test/Kconfig
18
test/Kconfig
|
@ -12,7 +12,23 @@ config UT_LIB
|
|||
default y
|
||||
help
|
||||
Enables the 'ut lib' command which tests library functions like
|
||||
memcat(), memcyp(), memmove().
|
||||
memcat(), memcyp(), memmove() and ASN1 compiler/decoder.
|
||||
|
||||
if UT_LIB
|
||||
|
||||
config UT_LIB_ASN1
|
||||
bool "Unit test for asn1 compiler and decoder function"
|
||||
default y
|
||||
imply ASYMMETRIC_KEY_TYPE
|
||||
imply ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
imply X509_CERTIFICATE_PARSER
|
||||
imply PKCS7_MESSAGE_PARSER
|
||||
imply RSA_PUBLIC_KEY_PARSER
|
||||
help
|
||||
Enables a test which exercises asn1 compiler and decoder function
|
||||
via various parsers.
|
||||
|
||||
endif
|
||||
|
||||
config UT_TIME
|
||||
bool "Unit tests for time functions"
|
||||
|
|
|
@ -7,3 +7,4 @@ obj-y += hexdump.o
|
|||
obj-y += lmb.o
|
||||
obj-y += string.o
|
||||
obj-$(CONFIG_ERRNO_STR) += test_errno_str.o
|
||||
obj-$(CONFIG_UT_LIB_ASN1) += asn1.o
|
||||
|
|
392
test/lib/asn1.c
Normal file
392
test/lib/asn1.c
Normal file
|
@ -0,0 +1,392 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (c) 2019 Linaro Limited
|
||||
* Author: AKASHI Takahiro
|
||||
*
|
||||
* Unit test for asn1 compiler and asn1 decoder function via various parsers
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <test/lib.h>
|
||||
#include <test/test.h>
|
||||
#include <test/ut.h>
|
||||
|
||||
#ifdef CONFIG_PKCS7_MESSAGE_PARSER
|
||||
#include "../../lib/crypto/pkcs7_parser.h"
|
||||
#else
|
||||
#ifdef CONFIG_X509_CERTIFICATE_PARSER
|
||||
#include "../../lib/crypto/x509_parser.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X509_CERTIFICATE_PARSER
|
||||
static const unsigned char cert_data[] = {
|
||||
0x30, 0x82, 0x03, 0xc7, 0x30, 0x82, 0x02, 0xaf, 0xa0, 0x03, 0x02, 0x01,
|
||||
0x02, 0x02, 0x09, 0x00, 0xd7, 0x17, 0x0a, 0x76, 0xd5, 0xd3, 0x4d, 0xeb,
|
||||
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
||||
0x0b, 0x05, 0x00, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
|
||||
0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03,
|
||||
0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31, 0x0e,
|
||||
0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f, 0x6b,
|
||||
0x79, 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
|
||||
0x06, 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06,
|
||||
0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30, 0x0d,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74, 0x65,
|
||||
0x72, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40, 0x74,
|
||||
0x65, 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d, 0x31,
|
||||
0x39, 0x31, 0x30, 0x31, 0x38, 0x30, 0x33, 0x31, 0x33, 0x33, 0x31, 0x5a,
|
||||
0x17, 0x0d, 0x32, 0x30, 0x31, 0x30, 0x31, 0x37, 0x30, 0x33, 0x31, 0x33,
|
||||
0x33, 0x31, 0x5a, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55,
|
||||
0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03,
|
||||
0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31, 0x0e,
|
||||
0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f, 0x6b,
|
||||
0x79, 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c,
|
||||
0x06, 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06,
|
||||
0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30, 0x0d,
|
||||
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74, 0x65,
|
||||
0x72, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||||
0x0d, 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40, 0x74,
|
||||
0x65, 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x82, 0x01, 0x22, 0x30,
|
||||
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
|
||||
0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02,
|
||||
0x82, 0x01, 0x01, 0x00, 0x9f, 0x37, 0x4d, 0x95, 0x7e, 0x36, 0xb7, 0xaf,
|
||||
0xf4, 0xd6, 0xce, 0x39, 0x04, 0xee, 0xbf, 0x36, 0xb2, 0xcc, 0xa3, 0x8b,
|
||||
0x9e, 0xac, 0x62, 0x8a, 0xe9, 0xae, 0x18, 0xcf, 0xe8, 0x95, 0xfd, 0xcb,
|
||||
0xad, 0x34, 0x8a, 0x5f, 0x55, 0xe6, 0x0c, 0x5e, 0xf8, 0x76, 0xc1, 0xa2,
|
||||
0xc3, 0xd4, 0x73, 0x13, 0x8a, 0x71, 0x1b, 0xfd, 0x58, 0x27, 0xea, 0x4d,
|
||||
0x41, 0xff, 0x63, 0xbb, 0xad, 0x97, 0x62, 0xba, 0xe4, 0xe5, 0x97, 0x45,
|
||||
0xa3, 0x5b, 0xd5, 0x5b, 0x53, 0x55, 0x10, 0x19, 0xfa, 0xac, 0xbd, 0xdb,
|
||||
0x77, 0x62, 0x23, 0x50, 0x3f, 0x35, 0xdb, 0x8a, 0xf6, 0xee, 0x7a, 0x31,
|
||||
0xec, 0x92, 0xf5, 0x78, 0x35, 0x92, 0x76, 0x3c, 0x5f, 0xe7, 0xee, 0xc9,
|
||||
0xed, 0x01, 0x1c, 0x42, 0x55, 0xd6, 0x7e, 0xa6, 0xca, 0x7c, 0xd1, 0x15,
|
||||
0x16, 0x87, 0x7c, 0x99, 0x63, 0xc0, 0xa9, 0x25, 0x49, 0xbc, 0x4e, 0xdc,
|
||||
0x2d, 0x4b, 0xcb, 0x52, 0xd7, 0x67, 0xe9, 0x83, 0x6b, 0x5e, 0x5b, 0x48,
|
||||
0x80, 0x33, 0xe9, 0xcc, 0xe8, 0xfe, 0x19, 0xc8, 0xc2, 0x61, 0x74, 0x52,
|
||||
0x25, 0x92, 0x48, 0xea, 0xad, 0x15, 0x16, 0x64, 0x6e, 0x53, 0x30, 0x77,
|
||||
0xa2, 0xef, 0x61, 0x92, 0x1b, 0x5e, 0xbe, 0x07, 0xf2, 0x3c, 0xf8, 0x35,
|
||||
0x7d, 0x76, 0x4f, 0x78, 0xa9, 0x2a, 0xf1, 0x32, 0xff, 0xec, 0x89, 0xa9,
|
||||
0x22, 0x4c, 0x3d, 0xc8, 0x65, 0xca, 0xf4, 0xa2, 0x6d, 0x3f, 0xa4, 0x0a,
|
||||
0xfa, 0x9e, 0xe4, 0xf0, 0xdb, 0x39, 0xb1, 0xf9, 0xf0, 0xfb, 0x04, 0x81,
|
||||
0x44, 0xa7, 0xd7, 0x61, 0xdf, 0x2d, 0x13, 0x45, 0x2c, 0xae, 0xf0, 0x0e,
|
||||
0xc4, 0x07, 0x5d, 0x7d, 0x2b, 0xb2, 0x20, 0x75, 0x33, 0x6b, 0x5b, 0xf7,
|
||||
0xe7, 0x17, 0x51, 0xf1, 0xab, 0xc1, 0x9e, 0xc6, 0xf0, 0x30, 0xc6, 0x25,
|
||||
0x26, 0x3e, 0xd7, 0xd7, 0xa3, 0xcc, 0x15, 0x95, 0x02, 0x03, 0x01, 0x00,
|
||||
0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
|
||||
0x04, 0x16, 0x04, 0x14, 0x45, 0x8a, 0x76, 0xf7, 0x4f, 0xf4, 0x0e, 0xa0,
|
||||
0xf2, 0x02, 0xe1, 0xe7, 0xe9, 0xc7, 0x7d, 0x51, 0x55, 0x92, 0x33, 0xcd,
|
||||
0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
|
||||
0x14, 0x45, 0x8a, 0x76, 0xf7, 0x4f, 0xf4, 0x0e, 0xa0, 0xf2, 0x02, 0xe1,
|
||||
0xe7, 0xe9, 0xc7, 0x7d, 0x51, 0x55, 0x92, 0x33, 0xcd, 0x30, 0x0c, 0x06,
|
||||
0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
|
||||
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
|
||||
0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x47, 0x93, 0x82, 0x0e, 0x8a,
|
||||
0x70, 0x9d, 0x6c, 0x7a, 0xdb, 0x04, 0xb4, 0xc9, 0xef, 0x98, 0x28, 0xc6,
|
||||
0xd9, 0x53, 0x90, 0xc8, 0x25, 0x83, 0x07, 0x23, 0xe7, 0x59, 0x38, 0xc1,
|
||||
0xc0, 0x50, 0x28, 0x99, 0x92, 0xfb, 0x21, 0x24, 0x72, 0xe5, 0xa6, 0x57,
|
||||
0x30, 0x31, 0xb3, 0xdf, 0xa0, 0x17, 0xa9, 0x73, 0x9c, 0x39, 0x83, 0xfb,
|
||||
0xe4, 0xfa, 0x20, 0x1d, 0xfa, 0x33, 0x20, 0x0c, 0x72, 0x2a, 0x50, 0x40,
|
||||
0xbd, 0x2d, 0x33, 0xa2, 0xfc, 0x06, 0xf9, 0xfe, 0x86, 0x4f, 0x50, 0x1d,
|
||||
0x65, 0x37, 0xe9, 0x30, 0x33, 0x82, 0xa1, 0x75, 0x8f, 0x5d, 0x33, 0x84,
|
||||
0x0d, 0xf2, 0x09, 0x04, 0xc0, 0x7a, 0x12, 0x79, 0xdb, 0x4f, 0x77, 0x04,
|
||||
0xe4, 0xd8, 0x0b, 0x87, 0x19, 0xba, 0xb7, 0x3c, 0xa6, 0x45, 0xaa, 0x91,
|
||||
0x62, 0x7f, 0x01, 0x7d, 0xc6, 0x20, 0x6d, 0x71, 0x15, 0x74, 0x5e, 0x87,
|
||||
0xb3, 0x60, 0x17, 0x9c, 0xc0, 0xed, 0x01, 0x4b, 0xb3, 0x23, 0x24, 0xc1,
|
||||
0xcb, 0x7a, 0x83, 0x03, 0x26, 0x2d, 0xde, 0x47, 0xc5, 0x11, 0x94, 0x28,
|
||||
0x27, 0x15, 0x92, 0x00, 0x8b, 0x2e, 0x51, 0x42, 0xca, 0x4b, 0x4a, 0x2c,
|
||||
0x51, 0x37, 0x56, 0xd0, 0xbc, 0x33, 0xd5, 0xd5, 0x3e, 0x79, 0x5c, 0x3f,
|
||||
0x9d, 0x6e, 0xb1, 0xe9, 0x71, 0xf1, 0x2c, 0xe9, 0xb4, 0x88, 0x2c, 0xd2,
|
||||
0x49, 0x97, 0xce, 0x29, 0x94, 0x16, 0xc9, 0xf9, 0x64, 0x0e, 0xd0, 0xd9,
|
||||
0x7a, 0x53, 0x10, 0x1a, 0xee, 0x83, 0x73, 0x93, 0x1b, 0xdf, 0x8a, 0x77,
|
||||
0xc0, 0x56, 0x63, 0xab, 0x5a, 0x65, 0xc5, 0xc5, 0x3b, 0xf3, 0x30, 0x80,
|
||||
0xfc, 0x38, 0x8b, 0xc9, 0xcd, 0xc3, 0x4f, 0x2e, 0x2d, 0x67, 0xcc, 0x17,
|
||||
0x18, 0x9b, 0x3e, 0xc6, 0x47, 0x03, 0xfc, 0x35, 0xa8, 0x35, 0x06, 0x5a,
|
||||
0x77, 0xe5, 0x97, 0x71, 0xbb, 0x27, 0x93, 0x0d, 0x1f, 0x0e, 0x8c
|
||||
};
|
||||
|
||||
static unsigned int cert_data_len = 971;
|
||||
|
||||
/**
|
||||
* lib_asn1_x509() - unit test for asn1 decoder function
|
||||
* with x509 certificate parser
|
||||
*
|
||||
* @uts: unit test state
|
||||
* Return: 0 = success, 1 = failure
|
||||
*/
|
||||
static int lib_asn1_x509(struct unit_test_state *uts)
|
||||
{
|
||||
struct x509_certificate *cert;
|
||||
|
||||
cert = x509_cert_parse(cert_data, cert_data_len);
|
||||
|
||||
ut_assertf(cert != NULL, "decoding failed\n");
|
||||
ut_assertf(!strcmp(cert->subject, "Linaro: Tester"),
|
||||
"subject doesn't match\n");
|
||||
ut_assertf(!strcmp(cert->issuer, "Linaro: Tester"),
|
||||
"issuer doesn't match\n");
|
||||
ut_assertf(cert->pub, "public key doesn't exist\n");
|
||||
ut_assertf(cert->pub->keylen == 0x10e, "key length doesn't match\n");
|
||||
ut_assertf(!strcmp(cert->pub->pkey_algo, "rsa"), "algo isn't rsa\n");
|
||||
ut_assertf(cert->valid_from == 0x5da92ddb,
|
||||
"valid_from doesn't match\n");
|
||||
ut_assertf(cert->valid_to == 0x5f8a615b, "valid_to doesn't match\n");
|
||||
|
||||
x509_free_certificate(cert);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
LIB_TEST(lib_asn1_x509, 0);
|
||||
#endif /* CONFIG_X509_CERTIFICATE_PARSER */
|
||||
|
||||
#ifdef CONFIG_PKCS7_MESSAGE_PARSER
|
||||
/*
|
||||
* sbsign --key priv.pem --cert cert.pem --detach --out Image.pk Image
|
||||
*/
|
||||
static const unsigned char image_pk7[] = {
|
||||
0x30, 0x82, 0x07, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
||||
0x01, 0x07, 0x02, 0xa0, 0x82, 0x07, 0x00, 0x30, 0x82, 0x06, 0xfc, 0x02,
|
||||
0x01, 0x01, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
|
||||
0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x30, 0x78, 0x06, 0x0a, 0x2b,
|
||||
0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02, 0x01, 0x04, 0xa0, 0x6a, 0x30,
|
||||
0x68, 0x30, 0x33, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37,
|
||||
0x02, 0x01, 0x0f, 0x30, 0x25, 0x03, 0x01, 0x00, 0xa0, 0x20, 0xa2, 0x1e,
|
||||
0x80, 0x1c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f, 0x00, 0x62,
|
||||
0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x74, 0x00, 0x65,
|
||||
0x00, 0x3e, 0x00, 0x3e, 0x00, 0x3e, 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04,
|
||||
0x20, 0x9e, 0x90, 0x99, 0x6d, 0xf2, 0xb5, 0x3d, 0x3f, 0xfc, 0x38, 0xb6,
|
||||
0xf2, 0x1f, 0xd2, 0x24, 0x88, 0x43, 0x77, 0x7d, 0xc1, 0x2c, 0x9e, 0x8a,
|
||||
0xf6, 0xf7, 0xdd, 0x9e, 0x9c, 0x5f, 0x18, 0x36, 0xc5, 0xa0, 0x82, 0x03,
|
||||
0xcb, 0x30, 0x82, 0x03, 0xc7, 0x30, 0x82, 0x02, 0xaf, 0xa0, 0x03, 0x02,
|
||||
0x01, 0x02, 0x02, 0x09, 0x00, 0xd7, 0x17, 0x0a, 0x76, 0xd5, 0xd3, 0x4d,
|
||||
0xeb, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
||||
0x01, 0x0b, 0x05, 0x00, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
|
||||
0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06,
|
||||
0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31,
|
||||
0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f,
|
||||
0x6b, 0x79, 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
||||
0x0c, 0x06, 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09,
|
||||
0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30,
|
||||
0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74,
|
||||
0x65, 0x72, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||||
0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40,
|
||||
0x74, 0x65, 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x1e, 0x17, 0x0d,
|
||||
0x31, 0x39, 0x31, 0x30, 0x31, 0x38, 0x30, 0x33, 0x31, 0x33, 0x33, 0x31,
|
||||
0x5a, 0x17, 0x0d, 0x32, 0x30, 0x31, 0x30, 0x31, 0x37, 0x30, 0x33, 0x31,
|
||||
0x33, 0x33, 0x31, 0x5a, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
|
||||
0x55, 0x04, 0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06,
|
||||
0x03, 0x55, 0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31,
|
||||
0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f,
|
||||
0x6b, 0x79, 0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a,
|
||||
0x0c, 0x06, 0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09,
|
||||
0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30,
|
||||
0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74,
|
||||
0x65, 0x72, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
|
||||
0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40,
|
||||
0x74, 0x65, 0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x82, 0x01, 0x22,
|
||||
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
||||
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a,
|
||||
0x02, 0x82, 0x01, 0x01, 0x00, 0x9f, 0x37, 0x4d, 0x95, 0x7e, 0x36, 0xb7,
|
||||
0xaf, 0xf4, 0xd6, 0xce, 0x39, 0x04, 0xee, 0xbf, 0x36, 0xb2, 0xcc, 0xa3,
|
||||
0x8b, 0x9e, 0xac, 0x62, 0x8a, 0xe9, 0xae, 0x18, 0xcf, 0xe8, 0x95, 0xfd,
|
||||
0xcb, 0xad, 0x34, 0x8a, 0x5f, 0x55, 0xe6, 0x0c, 0x5e, 0xf8, 0x76, 0xc1,
|
||||
0xa2, 0xc3, 0xd4, 0x73, 0x13, 0x8a, 0x71, 0x1b, 0xfd, 0x58, 0x27, 0xea,
|
||||
0x4d, 0x41, 0xff, 0x63, 0xbb, 0xad, 0x97, 0x62, 0xba, 0xe4, 0xe5, 0x97,
|
||||
0x45, 0xa3, 0x5b, 0xd5, 0x5b, 0x53, 0x55, 0x10, 0x19, 0xfa, 0xac, 0xbd,
|
||||
0xdb, 0x77, 0x62, 0x23, 0x50, 0x3f, 0x35, 0xdb, 0x8a, 0xf6, 0xee, 0x7a,
|
||||
0x31, 0xec, 0x92, 0xf5, 0x78, 0x35, 0x92, 0x76, 0x3c, 0x5f, 0xe7, 0xee,
|
||||
0xc9, 0xed, 0x01, 0x1c, 0x42, 0x55, 0xd6, 0x7e, 0xa6, 0xca, 0x7c, 0xd1,
|
||||
0x15, 0x16, 0x87, 0x7c, 0x99, 0x63, 0xc0, 0xa9, 0x25, 0x49, 0xbc, 0x4e,
|
||||
0xdc, 0x2d, 0x4b, 0xcb, 0x52, 0xd7, 0x67, 0xe9, 0x83, 0x6b, 0x5e, 0x5b,
|
||||
0x48, 0x80, 0x33, 0xe9, 0xcc, 0xe8, 0xfe, 0x19, 0xc8, 0xc2, 0x61, 0x74,
|
||||
0x52, 0x25, 0x92, 0x48, 0xea, 0xad, 0x15, 0x16, 0x64, 0x6e, 0x53, 0x30,
|
||||
0x77, 0xa2, 0xef, 0x61, 0x92, 0x1b, 0x5e, 0xbe, 0x07, 0xf2, 0x3c, 0xf8,
|
||||
0x35, 0x7d, 0x76, 0x4f, 0x78, 0xa9, 0x2a, 0xf1, 0x32, 0xff, 0xec, 0x89,
|
||||
0xa9, 0x22, 0x4c, 0x3d, 0xc8, 0x65, 0xca, 0xf4, 0xa2, 0x6d, 0x3f, 0xa4,
|
||||
0x0a, 0xfa, 0x9e, 0xe4, 0xf0, 0xdb, 0x39, 0xb1, 0xf9, 0xf0, 0xfb, 0x04,
|
||||
0x81, 0x44, 0xa7, 0xd7, 0x61, 0xdf, 0x2d, 0x13, 0x45, 0x2c, 0xae, 0xf0,
|
||||
0x0e, 0xc4, 0x07, 0x5d, 0x7d, 0x2b, 0xb2, 0x20, 0x75, 0x33, 0x6b, 0x5b,
|
||||
0xf7, 0xe7, 0x17, 0x51, 0xf1, 0xab, 0xc1, 0x9e, 0xc6, 0xf0, 0x30, 0xc6,
|
||||
0x25, 0x26, 0x3e, 0xd7, 0xd7, 0xa3, 0xcc, 0x15, 0x95, 0x02, 0x03, 0x01,
|
||||
0x00, 0x01, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
|
||||
0x0e, 0x04, 0x16, 0x04, 0x14, 0x45, 0x8a, 0x76, 0xf7, 0x4f, 0xf4, 0x0e,
|
||||
0xa0, 0xf2, 0x02, 0xe1, 0xe7, 0xe9, 0xc7, 0x7d, 0x51, 0x55, 0x92, 0x33,
|
||||
0xcd, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
|
||||
0x80, 0x14, 0x45, 0x8a, 0x76, 0xf7, 0x4f, 0xf4, 0x0e, 0xa0, 0xf2, 0x02,
|
||||
0xe1, 0xe7, 0xe9, 0xc7, 0x7d, 0x51, 0x55, 0x92, 0x33, 0xcd, 0x30, 0x0c,
|
||||
0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
|
||||
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
||||
0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x47, 0x93, 0x82, 0x0e,
|
||||
0x8a, 0x70, 0x9d, 0x6c, 0x7a, 0xdb, 0x04, 0xb4, 0xc9, 0xef, 0x98, 0x28,
|
||||
0xc6, 0xd9, 0x53, 0x90, 0xc8, 0x25, 0x83, 0x07, 0x23, 0xe7, 0x59, 0x38,
|
||||
0xc1, 0xc0, 0x50, 0x28, 0x99, 0x92, 0xfb, 0x21, 0x24, 0x72, 0xe5, 0xa6,
|
||||
0x57, 0x30, 0x31, 0xb3, 0xdf, 0xa0, 0x17, 0xa9, 0x73, 0x9c, 0x39, 0x83,
|
||||
0xfb, 0xe4, 0xfa, 0x20, 0x1d, 0xfa, 0x33, 0x20, 0x0c, 0x72, 0x2a, 0x50,
|
||||
0x40, 0xbd, 0x2d, 0x33, 0xa2, 0xfc, 0x06, 0xf9, 0xfe, 0x86, 0x4f, 0x50,
|
||||
0x1d, 0x65, 0x37, 0xe9, 0x30, 0x33, 0x82, 0xa1, 0x75, 0x8f, 0x5d, 0x33,
|
||||
0x84, 0x0d, 0xf2, 0x09, 0x04, 0xc0, 0x7a, 0x12, 0x79, 0xdb, 0x4f, 0x77,
|
||||
0x04, 0xe4, 0xd8, 0x0b, 0x87, 0x19, 0xba, 0xb7, 0x3c, 0xa6, 0x45, 0xaa,
|
||||
0x91, 0x62, 0x7f, 0x01, 0x7d, 0xc6, 0x20, 0x6d, 0x71, 0x15, 0x74, 0x5e,
|
||||
0x87, 0xb3, 0x60, 0x17, 0x9c, 0xc0, 0xed, 0x01, 0x4b, 0xb3, 0x23, 0x24,
|
||||
0xc1, 0xcb, 0x7a, 0x83, 0x03, 0x26, 0x2d, 0xde, 0x47, 0xc5, 0x11, 0x94,
|
||||
0x28, 0x27, 0x15, 0x92, 0x00, 0x8b, 0x2e, 0x51, 0x42, 0xca, 0x4b, 0x4a,
|
||||
0x2c, 0x51, 0x37, 0x56, 0xd0, 0xbc, 0x33, 0xd5, 0xd5, 0x3e, 0x79, 0x5c,
|
||||
0x3f, 0x9d, 0x6e, 0xb1, 0xe9, 0x71, 0xf1, 0x2c, 0xe9, 0xb4, 0x88, 0x2c,
|
||||
0xd2, 0x49, 0x97, 0xce, 0x29, 0x94, 0x16, 0xc9, 0xf9, 0x64, 0x0e, 0xd0,
|
||||
0xd9, 0x7a, 0x53, 0x10, 0x1a, 0xee, 0x83, 0x73, 0x93, 0x1b, 0xdf, 0x8a,
|
||||
0x77, 0xc0, 0x56, 0x63, 0xab, 0x5a, 0x65, 0xc5, 0xc5, 0x3b, 0xf3, 0x30,
|
||||
0x80, 0xfc, 0x38, 0x8b, 0xc9, 0xcd, 0xc3, 0x4f, 0x2e, 0x2d, 0x67, 0xcc,
|
||||
0x17, 0x18, 0x9b, 0x3e, 0xc6, 0x47, 0x03, 0xfc, 0x35, 0xa8, 0x35, 0x06,
|
||||
0x5a, 0x77, 0xe5, 0x97, 0x71, 0xbb, 0x27, 0x93, 0x0d, 0x1f, 0x0e, 0x8c,
|
||||
0x31, 0x82, 0x02, 0x9b, 0x30, 0x82, 0x02, 0x97, 0x02, 0x01, 0x01, 0x30,
|
||||
0x81, 0x87, 0x30, 0x7a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
|
||||
0x06, 0x13, 0x02, 0x4a, 0x50, 0x31, 0x0e, 0x30, 0x0c, 0x06, 0x03, 0x55,
|
||||
0x04, 0x08, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x31, 0x0e, 0x30,
|
||||
0x0c, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x05, 0x54, 0x6f, 0x6b, 0x79,
|
||||
0x6f, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06,
|
||||
0x4c, 0x69, 0x6e, 0x61, 0x72, 0x6f, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
|
||||
0x55, 0x04, 0x0b, 0x0c, 0x02, 0x53, 0x57, 0x31, 0x0f, 0x30, 0x0d, 0x06,
|
||||
0x03, 0x55, 0x04, 0x03, 0x0c, 0x06, 0x54, 0x65, 0x73, 0x74, 0x65, 0x72,
|
||||
0x31, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
||||
0x01, 0x09, 0x01, 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x40, 0x74, 0x65,
|
||||
0x73, 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x02, 0x09, 0x00, 0xd7, 0x17, 0x0a,
|
||||
0x76, 0xd5, 0xd3, 0x4d, 0xeb, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
|
||||
0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xa0, 0x81, 0xe5, 0x30,
|
||||
0x19, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x03,
|
||||
0x31, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x02,
|
||||
0x01, 0x04, 0x30, 0x1c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
||||
0x01, 0x09, 0x05, 0x31, 0x0f, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x30, 0x31,
|
||||
0x38, 0x30, 0x35, 0x35, 0x35, 0x32, 0x36, 0x5a, 0x30, 0x2f, 0x06, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x04, 0x31, 0x22, 0x04,
|
||||
0x20, 0x13, 0xe9, 0x2d, 0xcd, 0x35, 0x43, 0xe0, 0x13, 0x34, 0xc5, 0x67,
|
||||
0xde, 0xdd, 0x75, 0xdc, 0x62, 0x97, 0x76, 0x7d, 0x5b, 0xa0, 0xb4, 0x4d,
|
||||
0x4f, 0xef, 0xb8, 0xa7, 0x95, 0x50, 0xcb, 0x0f, 0xec, 0x30, 0x79, 0x06,
|
||||
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x0f, 0x31, 0x6c,
|
||||
0x30, 0x6a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
|
||||
0x04, 0x01, 0x2a, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
|
||||
0x03, 0x04, 0x01, 0x16, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
|
||||
0x65, 0x03, 0x04, 0x01, 0x02, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48,
|
||||
0x86, 0xf7, 0x0d, 0x03, 0x07, 0x30, 0x0e, 0x06, 0x08, 0x2a, 0x86, 0x48,
|
||||
0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x02, 0x00, 0x80, 0x30, 0x0d, 0x06,
|
||||
0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x01, 0x40,
|
||||
0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x07, 0x30, 0x0d, 0x06,
|
||||
0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x02, 0x02, 0x01, 0x28,
|
||||
0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
|
||||
0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x00, 0x38, 0x40, 0x09, 0xc7, 0xc4,
|
||||
0xf7, 0x78, 0x48, 0x75, 0x1e, 0xb2, 0x50, 0x95, 0x0a, 0x52, 0xee, 0x57,
|
||||
0x60, 0xc5, 0xf4, 0xdb, 0xca, 0x67, 0xb0, 0x19, 0xad, 0x68, 0xb1, 0xe1,
|
||||
0x1e, 0xb7, 0xf6, 0x53, 0x3d, 0x13, 0xb1, 0x11, 0x37, 0xa7, 0x6e, 0x9b,
|
||||
0x18, 0x1d, 0x0e, 0xbd, 0xc4, 0xb2, 0xd0, 0x36, 0x6c, 0x0c, 0x5a, 0x11,
|
||||
0x50, 0xcc, 0xdb, 0x1f, 0x6b, 0xcb, 0x28, 0x80, 0xd5, 0x3c, 0x4f, 0x93,
|
||||
0x0b, 0xd1, 0x45, 0x75, 0xa1, 0x89, 0x00, 0x71, 0x7d, 0x55, 0xcc, 0x1c,
|
||||
0x0a, 0xc9, 0xc4, 0xe6, 0x87, 0xf2, 0x87, 0x0d, 0x2e, 0x79, 0x71, 0x85,
|
||||
0x01, 0xd7, 0x32, 0x87, 0x9a, 0x11, 0xc6, 0x9a, 0xbb, 0x0a, 0x7b, 0xce,
|
||||
0xfe, 0xc8, 0xee, 0x10, 0x3c, 0xa6, 0x47, 0xdd, 0xbb, 0xa7, 0xf5, 0x19,
|
||||
0x50, 0xd5, 0x2a, 0x11, 0x44, 0x2f, 0x65, 0x09, 0x69, 0x50, 0xfa, 0xbd,
|
||||
0x02, 0xe4, 0x90, 0xdc, 0x2a, 0x7c, 0xdb, 0x82, 0x03, 0xa5, 0x28, 0x91,
|
||||
0x74, 0x7c, 0xd3, 0x83, 0xc8, 0x11, 0x1a, 0x14, 0x1b, 0xba, 0xb1, 0x82,
|
||||
0xbd, 0x53, 0xad, 0x9c, 0x34, 0x05, 0xfa, 0x2d, 0x14, 0x58, 0x5e, 0x50,
|
||||
0x64, 0x60, 0x5c, 0x21, 0x7c, 0xe6, 0xf0, 0x2b, 0xa2, 0xec, 0xe5, 0xeb,
|
||||
0xda, 0x88, 0xe2, 0x19, 0x36, 0x96, 0x65, 0xf7, 0x4c, 0x62, 0x9b, 0x75,
|
||||
0x24, 0xb4, 0xb1, 0x34, 0x83, 0xba, 0x05, 0x01, 0xd8, 0xe1, 0x33, 0xd3,
|
||||
0x1a, 0xd6, 0x09, 0x84, 0x31, 0xd0, 0x67, 0xf3, 0x3b, 0x0e, 0x19, 0x98,
|
||||
0x7e, 0x07, 0xdc, 0xe1, 0xd8, 0x45, 0x84, 0xa2, 0xdd, 0x8a, 0x04, 0x6a,
|
||||
0x43, 0xcf, 0xff, 0x7c, 0x9e, 0x83, 0xa8, 0x5d, 0xbc, 0x1f, 0x45, 0x86,
|
||||
0x5b, 0x2d, 0xcd, 0x9d, 0xa0, 0xba, 0x4d, 0xd2, 0xc6, 0xb9, 0xc5, 0x34,
|
||||
0x39, 0x29, 0x20, 0xee, 0x27, 0x60, 0x46, 0x9c, 0x62, 0xbe, 0xf2
|
||||
};
|
||||
|
||||
static unsigned int image_pk7_len = 1811;
|
||||
|
||||
/**
|
||||
* lib_asn1_pkcs7() - unit test for asn1 decoder function
|
||||
* with pkcs7 message parser
|
||||
*
|
||||
* @uts: unit test state
|
||||
* Return: 0 = success, 1 = failure
|
||||
*/
|
||||
static int lib_asn1_pkcs7(struct unit_test_state *uts)
|
||||
{
|
||||
struct pkcs7_message *pkcs7;
|
||||
|
||||
pkcs7 = pkcs7_parse_message(image_pk7, image_pk7_len);
|
||||
|
||||
ut_assertf(pkcs7 != NULL, "decoding failed\n");
|
||||
ut_assertf(pkcs7->data_len == 104, "signature size doesn't match\n");
|
||||
ut_assertf(pkcs7->signed_infos != NULL, "sign-info doesn't exist\n");
|
||||
ut_assertf(pkcs7->signed_infos->msgdigest_len == 32,
|
||||
"digest size doesn't match\n");
|
||||
ut_assertf(pkcs7->signed_infos->aa_set == 0xf,
|
||||
"authenticated attributes doesn't match\n");
|
||||
|
||||
pkcs7_free_message(pkcs7);
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
LIB_TEST(lib_asn1_pkcs7, 0);
|
||||
#endif /* CONFIG_PKCS7_MESSAGE_PARSER */
|
||||
|
||||
#ifdef CONFIG_RSA_PUBLIC_KEY_PARSER
|
||||
#include <crypto/internal/rsa.h>
|
||||
|
||||
/*
|
||||
* openssl genrsa 2048 -out private.pem
|
||||
* openssl rsa -in private.pem -pubout -outform der -out public.der
|
||||
* dd if=public.der of=public.raw bs=24 skip=1
|
||||
*/
|
||||
static const unsigned char public_key[] = {
|
||||
0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xca, 0x25, 0x23,
|
||||
0xe0, 0x0a, 0x4d, 0x8f, 0x56, 0xfc, 0xc9, 0x06, 0x4c, 0xcc, 0x94, 0x43,
|
||||
0xe0, 0x56, 0x44, 0x6e, 0x37, 0x54, 0x87, 0x12, 0x84, 0xf9, 0x07, 0x4f,
|
||||
0xe4, 0x23, 0x40, 0xc3, 0x43, 0x84, 0x37, 0x86, 0xd3, 0x9d, 0x95, 0x1c,
|
||||
0xe4, 0x8a, 0x66, 0x02, 0x09, 0xe2, 0x3d, 0xce, 0x2c, 0xc6, 0x02, 0x6a,
|
||||
0xd4, 0x65, 0x61, 0xff, 0x85, 0x6f, 0x88, 0x63, 0xba, 0x31, 0x62, 0x1e,
|
||||
0xb7, 0x95, 0xe9, 0x08, 0x3c, 0xe9, 0x35, 0xde, 0xfd, 0x65, 0x92, 0xb8,
|
||||
0x9e, 0x71, 0xa4, 0xcd, 0x47, 0xfd, 0x04, 0x26, 0xb9, 0x78, 0xbf, 0x05,
|
||||
0x0d, 0xfc, 0x00, 0x84, 0x08, 0xfc, 0xc4, 0x4b, 0xea, 0xf5, 0x97, 0x68,
|
||||
0x0d, 0x97, 0xd7, 0xff, 0x4f, 0x92, 0x82, 0xd7, 0xbb, 0xef, 0xb7, 0x67,
|
||||
0x8e, 0x72, 0x54, 0xe8, 0xc5, 0x9e, 0xfd, 0xd8, 0x38, 0xe9, 0xbe, 0x19,
|
||||
0x37, 0x5b, 0x36, 0x8b, 0xbf, 0x49, 0xa1, 0x59, 0x3a, 0x9d, 0xad, 0x92,
|
||||
0x08, 0x0b, 0xe3, 0xa4, 0xa4, 0x7d, 0xd3, 0x70, 0xc0, 0xb8, 0xfb, 0xc7,
|
||||
0xda, 0xd3, 0x19, 0x86, 0x37, 0x9a, 0xcd, 0xab, 0x30, 0x96, 0xab, 0xa4,
|
||||
0xa2, 0x31, 0xa0, 0x38, 0xfb, 0xbf, 0x85, 0xd3, 0x24, 0x39, 0xed, 0xbf,
|
||||
0xe1, 0x31, 0xed, 0x6c, 0x39, 0xc1, 0xe5, 0x05, 0x2e, 0x12, 0x30, 0x36,
|
||||
0x73, 0x5d, 0x62, 0xf3, 0x82, 0xaf, 0x38, 0xc8, 0xca, 0xfa, 0xa1, 0x99,
|
||||
0x57, 0x3c, 0xe1, 0xc1, 0x7b, 0x05, 0x0b, 0xcc, 0x2e, 0xa9, 0x10, 0xc8,
|
||||
0x68, 0xbd, 0x27, 0xb6, 0x19, 0x9c, 0xd2, 0xad, 0xb3, 0x1f, 0xca, 0x35,
|
||||
0x6e, 0x84, 0x23, 0xa1, 0xe9, 0xa4, 0x4c, 0xab, 0x19, 0x09, 0x79, 0x6e,
|
||||
0x3c, 0x7b, 0x74, 0xfc, 0x33, 0x05, 0xcf, 0xa4, 0x2e, 0xeb, 0x55, 0x60,
|
||||
0x05, 0xc7, 0xcf, 0x3f, 0x92, 0xac, 0x2d, 0x69, 0x0b, 0x19, 0x16, 0x79,
|
||||
0x75, 0x02, 0x03, 0x01, 0x00, 0x01
|
||||
};
|
||||
|
||||
static unsigned int public_key_len = 270;
|
||||
|
||||
/**
|
||||
* lib_asn1_pkey() - unit test for asn1 decoder function
|
||||
* with RSA public key parser
|
||||
*
|
||||
* @uts: unit test state
|
||||
* Return: 0 = success, 1 = failure
|
||||
*/
|
||||
static int lib_asn1_pkey(struct unit_test_state *uts)
|
||||
{
|
||||
struct rsa_key pkey;
|
||||
int ret;
|
||||
|
||||
ret = rsa_parse_pub_key(&pkey, public_key, public_key_len);
|
||||
|
||||
ut_assertf(ret == 0, "decoding failed (%d)\n", ret);
|
||||
ut_assertf(pkey.n_sz == 257, "public key modulus size doesn't match\n");
|
||||
ut_assertf(pkey.e_sz == 3, "public key exponent size doesn't match\n");
|
||||
ut_assertf(pkey.e[0] == 0x01 && pkey.e[1] == 0x00 && pkey.e[2] == 0x01,
|
||||
"public key exponent doesn't match\n");
|
||||
|
||||
return CMD_RET_SUCCESS;
|
||||
}
|
||||
|
||||
LIB_TEST(lib_asn1_pkey, 0);
|
||||
#endif /* CONFIG_RSA_PUBLIC_KEY_PARSER */
|
|
@ -207,6 +207,9 @@ endif
|
|||
|
||||
hostprogs-$(CONFIG_MIPS) += mips-relocs
|
||||
|
||||
hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler
|
||||
HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
|
||||
|
||||
# We build some files with extra pedantic flags to try to minimize things
|
||||
# that won't build on some weird host compiler -- though there are lots of
|
||||
# exceptions for files that aren't complaint.
|
||||
|
|
1611
tools/asn1_compiler.c
Normal file
1611
tools/asn1_compiler.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue