mirror of https://github.com/wolfSSL/wolfssl.git
ASN.1 print: implementation to parse and print added
New API to parse and print DER/BER data from a buffer. Add an example to parse DER, Base64 and PEM files and print out ASN.1 items.pull/6352/head
parent
f8559b745e
commit
9cdee20a7d
|
@ -73,6 +73,7 @@ examples/sctp/sctp-server
|
|||
examples/sctp/sctp-server-dtls
|
||||
examples/sctp/sctp-client
|
||||
examples/sctp/sctp-client-dtls
|
||||
examples/asn1/asn1
|
||||
server_ready
|
||||
snifftest
|
||||
output
|
||||
|
|
21
configure.ac
21
configure.ac
|
@ -4016,6 +4016,26 @@ else
|
|||
ENABLED_BIGNUM="yes"
|
||||
fi
|
||||
|
||||
case $host_os in
|
||||
*linux* | *darwin* | *freebsd*)
|
||||
DEF_ASN_PRINT="yes"
|
||||
;;
|
||||
*)
|
||||
DEF_ASN_PRINT="no"
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_ARG_ENABLE([asn-print],
|
||||
[AS_HELP_STRING([--enable-asn-print],[Enable ASN Print API (default: enabled)])],
|
||||
[ ENABLED_ASN_PRINT=$enableval ],
|
||||
[ ENABLED_ASN_PRINT=$DEF_ASN_PRINT ]
|
||||
)
|
||||
|
||||
if test "$ENABLED_ASN_PRINT" = "yes"
|
||||
then
|
||||
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_ASN_PRINT"
|
||||
fi
|
||||
|
||||
|
||||
# AES
|
||||
AC_ARG_ENABLE([aes],
|
||||
|
@ -8496,6 +8516,7 @@ AM_CONDITIONAL([BUILD_FASTMATH],[test "x$ENABLED_FASTMATH" = "xyes" || test "x$E
|
|||
AM_CONDITIONAL([BUILD_HEAPMATH],[test "x$ENABLED_HEAPMATH" = "xyes" || test "x$ENABLED_USERSETTINGS" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_EXAMPLE_SERVERS],[test "x$ENABLED_EXAMPLES" = "xyes" && test "x$ENABLED_LEANTLS" = "xno"])
|
||||
AM_CONDITIONAL([BUILD_EXAMPLE_CLIENTS],[test "x$ENABLED_EXAMPLES" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_EXAMPLE_ASN1],[test "x$ENABLED_EXAMPLES" = "xyes"] && [test "x$ENABLED_ASN_PRINT" = "xyes"] && [test "x$ENABLED_ASN" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_TESTS],[test "x$ENABLED_EXAMPLES" = "xyes"])
|
||||
AM_CONDITIONAL([BUILD_THREADED_EXAMPLES],[test "x$ENABLED_SINGLETHREADED" = "xno" && test "x$ENABLED_EXAMPLES" = "xyes" && test "x$ENABLED_LEANTLS" = "xno"])
|
||||
AM_CONDITIONAL([BUILD_WOLFCRYPT_TESTS],[test "x$ENABLED_CRYPT_TESTS" = "xyes"])
|
||||
|
|
|
@ -2167,3 +2167,148 @@ int wc_SetUnknownExtCallback(DecodedCert* cert,
|
|||
int wc_CheckCertSigPubKey(const byte* cert, word32 certSz,
|
||||
void* heap, const byte* pubKey,
|
||||
word32 pubKeySz, int pubKeyOID);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function initializes the ASN.1 print options.
|
||||
|
||||
\return 0 on success.
|
||||
\return BAD_FUNC_ARG when asn1 is NULL.
|
||||
|
||||
\param opts The ASN.1 options for printing.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
Asn1PrintOptions opt;
|
||||
|
||||
// Initialize ASN.1 print options before use.
|
||||
wc_Asn1PrintOptions_Init(&opt);
|
||||
\endcode
|
||||
|
||||
\sa wc_Asn1PrintOptions_Set
|
||||
\sa wc_Asn1_PrintAll
|
||||
*/
|
||||
int wc_Asn1PrintOptions_Init(Asn1PrintOptions* opts);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function sets a print option into an ASN.1 print options object.
|
||||
|
||||
\return 0 on success.
|
||||
\return BAD_FUNC_ARG when asn1 is NULL.
|
||||
\return BAD_FUNC_ARG when val is out of range for option.
|
||||
|
||||
\param opts The ASN.1 options for printing.
|
||||
\param opt An option to set value for.
|
||||
\param val The value to set.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
Asn1PrintOptions opt;
|
||||
|
||||
// Initialize ASN.1 print options before use.
|
||||
wc_Asn1PrintOptions_Init(&opt);
|
||||
// Set the number of indents when printing tag name to be 1.
|
||||
wc_Asn1PrintOptions_Set(&opt, ASN1_PRINT_OPT_INDENT, 1);
|
||||
\endcode
|
||||
|
||||
\sa wc_Asn1PrintOptions_Init
|
||||
\sa wc_Asn1_PrintAll
|
||||
*/
|
||||
int wc_Asn1PrintOptions_Set(Asn1PrintOptions* opts, enum Asn1PrintOpt opt,
|
||||
word32 val);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function initializes an ASN.1 parsing object.
|
||||
|
||||
\return 0 on success.
|
||||
\return BAD_FUNC_ARG when asn1 is NULL.
|
||||
|
||||
\param asn1 ASN.1 parse object.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
Asn1 asn1;
|
||||
|
||||
// Initialize ASN.1 parse object before use.
|
||||
wc_Asn1_Init(&asn1);
|
||||
\endcode
|
||||
|
||||
\sa wc_Asn1_SetFile
|
||||
\sa wc_Asn1_PrintAll
|
||||
*/
|
||||
int wc_Asn1_Init(Asn1* asn1);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief This function sets the file to use when printing into an ASN.1
|
||||
parsing object.
|
||||
|
||||
\return 0 on success.
|
||||
\return BAD_FUNC_ARG when asn1 is NULL.
|
||||
\return BAD_FUNC_ARG when file is XBADFILE.
|
||||
|
||||
\param asn1 The ASN.1 parse object.
|
||||
\param file File to print to.
|
||||
|
||||
_Example_
|
||||
\code
|
||||
Asn1 asn1;
|
||||
|
||||
// Initialize ASN.1 parse object before use.
|
||||
wc_Asn1_Init(&asn1);
|
||||
// Set standard out to be the file descriptor to write to.
|
||||
wc_Asn1_SetFile(&asn1, stdout);
|
||||
\endcode
|
||||
|
||||
\sa wc_Asn1_Init
|
||||
\sa wc_Asn1_PrintAll
|
||||
*/
|
||||
int wc_Asn1_SetFile(Asn1* asn1, XFILE file);
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
|
||||
\brief Print all ASN.1 items.
|
||||
|
||||
\return 0 on success.
|
||||
\return BAD_FUNC_ARG when asn1 or opts is NULL.
|
||||
\return ASN_LEN_E when ASN.1 item's length too long.
|
||||
\return ASN_DEPTH_E when end offset invalid.
|
||||
\return ASN_PARSE_E when not all of an ASN.1 item parsed.
|
||||
|
||||
\param asn1 The ASN.1 parse object.
|
||||
\param opts The ASN.1 print options.
|
||||
\param data Buffer containing BER/DER data to print.
|
||||
\param len Length of data to print in bytes.
|
||||
|
||||
\code
|
||||
Asn1PrintOptions opts;
|
||||
Asn1 asn1;
|
||||
unsigned char data[] = { Initialize with DER/BER data };
|
||||
word32 len = sizeof(data);
|
||||
|
||||
// Initialize ASN.1 print options before use.
|
||||
wc_Asn1PrintOptions_Init(&opt);
|
||||
// Set the number of indents when printing tag name to be 1.
|
||||
wc_Asn1PrintOptions_Set(&opt, ASN1_PRINT_OPT_INDENT, 1);
|
||||
|
||||
// Initialize ASN.1 parse object before use.
|
||||
wc_Asn1_Init(&asn1);
|
||||
// Set standard out to be the file descriptor to write to.
|
||||
wc_Asn1_SetFile(&asn1, stdout);
|
||||
// Print all ASN.1 items in buffer with the specified print options.
|
||||
wc_Asn1_PrintAll(&asn1, &opts, data, len);
|
||||
\endcode
|
||||
|
||||
\sa wc_Asn1_Init
|
||||
\sa wc_Asn1_SetFile
|
||||
*/
|
||||
int wc_Asn1_PrintAll(Asn1* asn1, Asn1PrintOptions* opts, unsigned char* data,
|
||||
word32 len);
|
||||
|
||||
|
|
|
@ -0,0 +1,494 @@
|
|||
/* asn1.c
|
||||
*
|
||||
* Copyright (C) 2006-2023 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifndef WOLFSSL_USER_SETTINGS
|
||||
#include <wolfssl/options.h>
|
||||
#endif
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
#include <wolfssl/wolfcrypt/asn_public.h>
|
||||
#include <wolfssl/wolfcrypt/coding.h>
|
||||
#include <wolfssl/wolfcrypt/error-crypt.h>
|
||||
|
||||
#ifdef WOLFSSL_ASN_PRINT
|
||||
|
||||
/* Increment allocated data by this much. */
|
||||
#define DATA_INC_LEN 256
|
||||
|
||||
|
||||
/* File format is DER/BER. */
|
||||
#define FORMAT_DER 0
|
||||
/* File format is BASE64. */
|
||||
#define FORMAT_BASE64 1
|
||||
/* File format is PEM. */
|
||||
#define FORMAT_PEM 2
|
||||
|
||||
/* ASN.1 print options. */
|
||||
static Asn1PrintOptions opts;
|
||||
/* ASN.1 parsing state. */
|
||||
static Asn1 asn1;
|
||||
|
||||
/* Read the contents of a file into a dynamically allocated buffer.
|
||||
*
|
||||
* Uses realloc as input may be stdin.
|
||||
*
|
||||
* @param [in] fp File pointer to read from.
|
||||
* @param [out] pdata Pointer to data.
|
||||
* @param [out] plen Pointer to length.
|
||||
* @return 0 on success.
|
||||
* @return 1 on failure.
|
||||
*/
|
||||
static int ReadFile(FILE* fp, unsigned char** pdata, word32* plen)
|
||||
{
|
||||
int ret = 0;
|
||||
word32 len = 0;
|
||||
size_t read_len;
|
||||
/* Allocate a minimum amount. */
|
||||
unsigned char* data = (unsigned char*)malloc(DATA_INC_LEN);
|
||||
|
||||
if (data != NULL) {
|
||||
/* Read more data. */
|
||||
while ((read_len = fread(data + len, 1, DATA_INC_LEN, fp)) != 0) {
|
||||
unsigned char* p;
|
||||
|
||||
/* Add read data amount to length. */
|
||||
len += (word32)read_len;
|
||||
|
||||
/* Stop if we are at end-of-file. */
|
||||
if (feof(fp)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make space for more data to be added to buffer. */
|
||||
p = (unsigned char*)realloc(data, len + DATA_INC_LEN);
|
||||
if (p == NULL) {
|
||||
/* Reallocation failed - free current buffer. */
|
||||
free(data);
|
||||
data = NULL;
|
||||
break;
|
||||
}
|
||||
/* Set data to new pointer. */
|
||||
data = p;
|
||||
}
|
||||
/* Done with file. */
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (data != NULL) {
|
||||
/* Return data and length. */
|
||||
*pdata = data;
|
||||
*plen = len;
|
||||
}
|
||||
else {
|
||||
/* Failed to allocate data. */
|
||||
ret = MEMORY_E;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Print ASN.1 of a file containing BER/DER data.
|
||||
*
|
||||
* @param [in] fp File pointer to read from.
|
||||
* @return 0 on success.
|
||||
* @return 1 on failure.
|
||||
*/
|
||||
static int PrintDer(FILE* fp)
|
||||
{
|
||||
int ret = 0;
|
||||
word32 len = 0;
|
||||
unsigned char* data = NULL;
|
||||
|
||||
/* Load DER/BER file. */
|
||||
if (ReadFile(fp, &data, &len) != 0) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if ((ret == 0) && (data != NULL)) {
|
||||
/* Print DER/BER. */
|
||||
ret = wc_Asn1_PrintAll(&asn1, &opts, data, len);
|
||||
/* Dispose of buffer. */
|
||||
free(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Print ASN.1 of a file containing Base64 encoding of BER/DER data.
|
||||
*
|
||||
* @param [in] fp File pointer to read from.
|
||||
* @return 0 on success.
|
||||
* @return 1 on failure.
|
||||
*/
|
||||
static int PrintBase64(FILE* fp)
|
||||
{
|
||||
int ret = 0;
|
||||
word32 len = 0;
|
||||
unsigned char* data = NULL;
|
||||
|
||||
/* Load Base64 encoded file. */
|
||||
if (ReadFile(fp, &data, &len) != 0) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if ((ret == 0) && (data != NULL)) {
|
||||
/* Decode Base64. */
|
||||
if (Base64_Decode(data, len, data, &len) != 0) {
|
||||
fprintf(stderr, "Invalid Base64 encoding\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* Print DER/BER. */
|
||||
ret = wc_Asn1_PrintAll(&asn1, &opts, data, len);
|
||||
}
|
||||
/* Dispose of buffer. */
|
||||
free(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Find the next PEM block.
|
||||
*
|
||||
* @param [in] data PEM data.
|
||||
* @param [in] offset Offset into data to start looking.
|
||||
* @param [in] len Length of PEM data.
|
||||
* @param [out] start Start of Base64 encoding.
|
||||
* @param [out] end End of Base64 encoding.
|
||||
*/
|
||||
static int FindPem(unsigned char* data, word32 offset, word32 len,
|
||||
word32* start, word32* end)
|
||||
{
|
||||
int ret = 0;
|
||||
word32 i;
|
||||
word32 j;
|
||||
|
||||
/* Find header. */
|
||||
for (i = offset; i < len; i++) {
|
||||
if ((data[i] == '-') &&
|
||||
(strncmp((char*)data + i, "-----BEGIN", 10) == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == len) {
|
||||
/* Got to end without finding PEM header. */
|
||||
fprintf(stderr, "No PEM header found\n");
|
||||
ret = 1;
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* Confirm header. */
|
||||
for (i += 10; i < len; i++) {
|
||||
if ((data[i] == '-') &&
|
||||
(strncmp((char*)data + i, "-----", 5) == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == len) {
|
||||
/* Got to end without finding rest of PEM header. */
|
||||
fprintf(stderr, "Invalid PEM header\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* Find footer. */
|
||||
i += 6;
|
||||
for (j = i + 1; j < len; j++) {
|
||||
if ((data[j] == '-') &&
|
||||
(strncmp((char*)data + j, "-----END", 8) == 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j == len) {
|
||||
/* Got to end without finding PEM footer. */
|
||||
fprintf(stderr, "No PEM footer found\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* Return start and end indeces. */
|
||||
*start = i;
|
||||
*end = j;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Print ASN.1 of file containing PEM.
|
||||
*
|
||||
* Only one block is printed.
|
||||
*
|
||||
* @param [in] fp File pointer to read from.
|
||||
* @param [in] pem_skip Number of PEM blocks to skip.
|
||||
* @return 0 on success.
|
||||
* @return 1 on failure.
|
||||
*/
|
||||
static int PrintPem(FILE* fp, int pem_skip)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned char* data = NULL;
|
||||
word32 len = 0;
|
||||
|
||||
/* Load PEM file. */
|
||||
if (ReadFile(fp, &data, &len) != 0) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if ((ret == 0) && (data != NULL)) {
|
||||
word32 i = 0;
|
||||
word32 j = 0;
|
||||
|
||||
/* Find PEM blocks and skip number requested. */
|
||||
do {
|
||||
/* Find start and end of PEM Base64 data. */
|
||||
ret = FindPem(data, j, len, &i, &j);
|
||||
} while ((ret == 0) && ((pem_skip--) != 0));
|
||||
|
||||
/* Decode data between header and footer. */
|
||||
if ((ret == 0) && (Base64_Decode(data + i, j - i, data, &len) != 0)) {
|
||||
fprintf(stderr, "Invalid Base64 encoding\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* Print DER/BER. */
|
||||
ret = wc_Asn1_PrintAll(&asn1, &opts, data, len);
|
||||
}
|
||||
/* Dispose of buffer. */
|
||||
free(data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Usage lines to show. */
|
||||
const char* usage[] = {
|
||||
"asn1 [OPTOIN]... [FILE]",
|
||||
"Display a human-readable version of a DER/BER encoding.",
|
||||
"",
|
||||
"Options:",
|
||||
" -?, --help display this help and exit",
|
||||
" -b, --branch draw branches before tag name",
|
||||
" -B, --base64 file contents are Base64 encoded",
|
||||
" -d, --dump show all ASN.1 item data as a hex dump",
|
||||
" -h, --headers show all ASN.1 item headers as a hex dump",
|
||||
" -i, --indent indent tag name with depth",
|
||||
" -l, --length LEN display length bytes of data",
|
||||
" -n, --no-text do not show data as text",
|
||||
" -N, --no-dump-text do not show data as a hex dump text",
|
||||
" -o, --offset OFFSET start decoding from offset",
|
||||
" -O, --oid show wolfSSL OID value in text",
|
||||
" -p, --pem file contents are PEM",
|
||||
" -s, --skip-pem NUM number of PEM blocks to skip",
|
||||
};
|
||||
/* Number of usage lines. */
|
||||
#define USAGE_SZ ((int)(sizeof(usage) / sizeof(*usage)))
|
||||
|
||||
/* Print out usage lines.
|
||||
*/
|
||||
static void Usage(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < USAGE_SZ; i++) {
|
||||
printf("%s\n", usage[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Main entry of ASN.1 printing program.
|
||||
*
|
||||
* @param [in] argc Count of command line argements.
|
||||
* @param [in] argv Command line argements.
|
||||
* @return 0 on success.
|
||||
* @return 1 on failure.
|
||||
*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
/* Default to reading STDIN. */
|
||||
FILE* fp = stdin;
|
||||
int file_format = FORMAT_DER;
|
||||
int indent = 0;
|
||||
int pem_skip = 0;
|
||||
|
||||
/* Reset options. */
|
||||
(void)wc_Asn1PrintOptions_Init(&opts);
|
||||
|
||||
/* Skip over program name. */
|
||||
argc--;
|
||||
argv++;
|
||||
while (argc > 0) {
|
||||
/* Show branches instead of indenting. */
|
||||
if ((strcmp(argv[0], "-b") == 0) ||
|
||||
(strcmp(argv[0], "--branch") == 0)) {
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_DRAW_BRANCH, 1);
|
||||
}
|
||||
/* File is Base64 encoded data. */
|
||||
else if ((strcmp(argv[0], "-b64") == 0) ||
|
||||
(strcmp(argv[0], "--base64") == 0)) {
|
||||
file_format = FORMAT_BASE64;
|
||||
}
|
||||
/* Dump all ASN.1 item data. */
|
||||
else if ((strcmp(argv[0], "-d") == 0) ||
|
||||
(strcmp(argv[0], "--dump") == 0)) {
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_SHOW_DATA, 1);
|
||||
}
|
||||
/* Dump ASN.1 item headers. */
|
||||
else if ((strcmp(argv[0], "-h") == 0) ||
|
||||
(strcmp(argv[0], "--headers") == 0)) {
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_SHOW_HEADER_DATA, 1);
|
||||
}
|
||||
/* Indent to text to indicate depth. */
|
||||
else if ((strcmp(argv[0], "-i") == 0) ||
|
||||
(strcmp(argv[0], "--indent") == 0)) {
|
||||
indent++;
|
||||
if (indent > 15) {
|
||||
}
|
||||
}
|
||||
/* Only parse the specified length of DER/BER data. */
|
||||
else if ((strcmp(argv[0], "-l") == 0) ||
|
||||
(strcmp(argv[0], "--length") == 0)) {
|
||||
if (argc == 1) {
|
||||
printf("Missing length value\n");
|
||||
return 1;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_LENGTH,
|
||||
atoi(argv[0]));
|
||||
}
|
||||
/* Do not show text representations of ASN.1 item data. */
|
||||
else if ((strcmp(argv[0], "-n") == 0) ||
|
||||
(strcmp(argv[0], "--no-text") == 0)) {
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_SHOW_NO_TEXT, 1);
|
||||
}
|
||||
/* Do not show hex dump text representations of ASN.1 item data. */
|
||||
else if ((strcmp(argv[0], "-N") == 0) ||
|
||||
(strcmp(argv[0], "--no-dump-text") == 0)) {
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_SHOW_NO_DUMP_TEXT, 1);
|
||||
}
|
||||
/* Offset into DER/BER to start decoding from. */
|
||||
else if ((strcmp(argv[0], "-o") == 0) ||
|
||||
(strcmp(argv[0], "--offset") == 0)) {
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, "Missing offset value\n");
|
||||
return 1;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_OFFSET,
|
||||
atoi(argv[0]));
|
||||
}
|
||||
/* Show wolfSSL OID value for all OBJECT_IDs. */
|
||||
else if ((strcmp(argv[0], "-O") == 0) ||
|
||||
(strcmp(argv[0], "--oid") == 0)) {
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_SHOW_OID, 1);
|
||||
}
|
||||
/* File contains PEM blocks. */
|
||||
else if ((strcmp(argv[0], "-p") == 0) ||
|
||||
(strcmp(argv[0], "--pem") == 0)) {
|
||||
file_format = FORMAT_PEM;
|
||||
}
|
||||
/* Skip a number of PEM blocks. */
|
||||
else if ((strcmp(argv[0], "-s") == 0) ||
|
||||
(strcmp(argv[0], "--skip-pem") == 0)) {
|
||||
if (argc == 1) {
|
||||
fprintf(stderr, "Missing number of PEM blocks to skip\n");
|
||||
return 1;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
pem_skip = atoi(argv[0]);
|
||||
if ((pem_skip < 0) || (pem_skip > 15)) {
|
||||
fprintf(stderr, "Skip value out of range: %d\n", pem_skip);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Display help/usage. */
|
||||
else if ((strcmp(argv[0], "-?") == 0) ||
|
||||
(strcmp(argv[0], "--help") == 0)) {
|
||||
Usage();
|
||||
return 0;
|
||||
}
|
||||
/* Unknown option dectection. */
|
||||
else if (argv[0][0] == '-') {
|
||||
fprintf(stderr, "Bad option: %s\n", argv[0]);
|
||||
Usage();
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
/* Name of file to read. */
|
||||
fp = fopen(argv[0], "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "File not able to be read: %s\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move on to next command line argument. */
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
wc_Asn1PrintOptions_Set(&opts, ASN1_PRINT_OPT_INDENT, indent);
|
||||
|
||||
(void)wc_Asn1_Init(&asn1);
|
||||
(void)wc_Asn1_SetFile(&asn1, stdout);
|
||||
|
||||
/* Process file based on type. */
|
||||
if (file_format == FORMAT_DER) {
|
||||
ret = PrintDer(fp);
|
||||
}
|
||||
else if (file_format == FORMAT_BASE64) {
|
||||
ret = PrintBase64(fp);
|
||||
}
|
||||
else if (file_format == FORMAT_PEM) {
|
||||
ret = PrintPem(fp, pem_skip);
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%s\n", wc_GetErrorString(ret));
|
||||
}
|
||||
return (ret == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Main entry of ASN.1 printing program.
|
||||
*
|
||||
* @param [in] argc Count of command line argements.
|
||||
* @param [in] argv Command line argements.
|
||||
* @return 0 on success.
|
||||
* @return 1 on failure.
|
||||
*/
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
fprintf(stderr, "ASN.1 Parsing and Printing not compiled in.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# vim:ft=automake
|
||||
# included from Top Level Makefile.am
|
||||
# All paths should be given relative to the root
|
||||
|
||||
|
||||
if BUILD_EXAMPLE_ASN1
|
||||
noinst_PROGRAMS += examples/asn1/asn1
|
||||
examples_asn1_asn1_SOURCES = examples/asn1/asn1.c
|
||||
examples_asn1_asn1_LDADD = src/libwolfssl@LIBSUFFIX@.la $(LIB_STATIC_ADD)
|
||||
examples_asn1_asn1_DEPENDENCIES = src/libwolfssl@LIBSUFFIX@.la
|
||||
endif
|
||||
|
|
@ -8,4 +8,5 @@ include examples/echoserver/include.am
|
|||
include examples/server/include.am
|
||||
include examples/sctp/include.am
|
||||
include examples/configs/include.am
|
||||
include examples/asn1/include.am
|
||||
EXTRA_DIST += examples/README.md
|
||||
|
|
|
@ -218,6 +218,88 @@ extern int wc_InitRsaHw(RsaKey* key);
|
|||
#endif /* HAVE_SELFTEST */
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_ASN_PRINT) || defined(WOLFSSL_DEBUG_ASN_TEMPLATE)
|
||||
|
||||
/* String representations of tags. */
|
||||
static const char* tagString[4][32] = {
|
||||
/* Universal */
|
||||
{
|
||||
"EOC",
|
||||
"BOOLEAN",
|
||||
"INTEGER",
|
||||
"BIT STRING",
|
||||
"OCTET STRING",
|
||||
"NULL",
|
||||
"OBJECT ID",
|
||||
"ObjectDescriptor",
|
||||
"INSTANCE OF",
|
||||
"REAL",
|
||||
"ENUMERATED",
|
||||
"EMBEDDED PDV",
|
||||
"UT8String",
|
||||
"RELATIVE-OID",
|
||||
"(0x0e) 14",
|
||||
"(0x0f) 15",
|
||||
"SEQUENCE",
|
||||
"SET",
|
||||
"NumericString",
|
||||
"PrintableString",
|
||||
"T61String",
|
||||
"VideotexString",
|
||||
"IA5String",
|
||||
"UTCTime",
|
||||
"GeneralizedTime",
|
||||
"GraphicString",
|
||||
"ISO646String",
|
||||
"GeneralString",
|
||||
"UniversalString",
|
||||
"CHARACTER STRING",
|
||||
"BMPString",
|
||||
"(0x1f) 31",
|
||||
},
|
||||
/* Application */
|
||||
{
|
||||
"[A 0]", "[A 1]", "[A 2]", "[A 3]",
|
||||
"[A 4]", "[A 5]", "[A 6]", "[A 7]",
|
||||
"[A 8]", "[A 9]", "[A 10]", "[A 11]",
|
||||
"[A 12]", "[A 13]", "[A 14]", "[A 15]",
|
||||
"[A 16]", "[A 17]", "[A 18]", "[A 19]",
|
||||
"[A 20]", "[A 21]", "[A 22]", "[A 23]",
|
||||
"[A 24]", "[A 25]", "[A 26]", "[A 27]",
|
||||
"[A 28]", "[A 20]", "[A 30]", "[A 31]"
|
||||
},
|
||||
/* Context-Specific */
|
||||
{
|
||||
"[0]", "[1]", "[2]", "[3]", "[4]", "[5]", "[6]", "[7]",
|
||||
"[8]", "[9]", "[10]", "[11]", "[12]", "[13]", "[14]", "[15]",
|
||||
"[16]", "[17]", "[18]", "[19]", "[20]", "[21]", "[22]", "[23]",
|
||||
"[24]", "[25]", "[26]", "[27]", "[28]", "[20]", "[30]", "[31]"
|
||||
},
|
||||
/* Private */
|
||||
{
|
||||
"[P 0]", "[P 1]", "[P 2]", "[P 3]",
|
||||
"[P 4]", "[P 5]", "[P 6]", "[P 7]",
|
||||
"[P 8]", "[P 9]", "[P 10]", "[P 11]",
|
||||
"[P 12]", "[P 13]", "[P 14]", "[P 15]",
|
||||
"[P 16]", "[P 17]", "[P 18]", "[P 19]",
|
||||
"[P 20]", "[P 21]", "[P 22]", "[P 23]",
|
||||
"[P 24]", "[P 25]", "[P 26]", "[P 27]",
|
||||
"[P 28]", "[P 20]", "[P 30]", "[P 31]"
|
||||
}
|
||||
};
|
||||
|
||||
/* Converts a tag byte to string.
|
||||
*
|
||||
* @param [in] tag BER tag value to interpret.
|
||||
* @return String corresponding to tag.
|
||||
*/
|
||||
static const char* TagString(byte tag)
|
||||
{
|
||||
return tagString[tag >> 6][tag & ASN_TYPE_MASK];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Calculates the minimum number of bytes required to encode the value.
|
||||
*
|
||||
|
@ -482,83 +564,6 @@ static word32 SizeASNLength(word32 length)
|
|||
#endif
|
||||
|
||||
#ifdef WOLFSSL_DEBUG_ASN_TEMPLATE
|
||||
/* String representations of tags. */
|
||||
static const char* tagString[4][32] = {
|
||||
/* Universal */
|
||||
{
|
||||
"EOC",
|
||||
"BOOLEAN",
|
||||
"INTEGER",
|
||||
"BIT STRING",
|
||||
"OCTET STRING",
|
||||
"NULL",
|
||||
"OBJECT ID",
|
||||
"ObjectDescriptor",
|
||||
"INSTANCE OF",
|
||||
"REAL",
|
||||
"ENUMERATED",
|
||||
"EMBEDDED PDV",
|
||||
"UT8String",
|
||||
"RELATIVE-OID",
|
||||
"(0x0e) 14",
|
||||
"(0x0f) 15",
|
||||
"SEQUENCE",
|
||||
"SET",
|
||||
"NumericString",
|
||||
"PrintableString",
|
||||
"T61String",
|
||||
"VideotexString",
|
||||
"IA5String",
|
||||
"UTCTime",
|
||||
"GeneralizedTime",
|
||||
"GraphicString",
|
||||
"ISO646String",
|
||||
"GeneralString",
|
||||
"UniversalString",
|
||||
"CHARACTER STRING",
|
||||
"BMPString",
|
||||
"(0x1f) 31",
|
||||
},
|
||||
/* Application */
|
||||
{
|
||||
"[A 0]", "[A 1]", "[A 2]", "[A 3]",
|
||||
"[A 4]", "[A 5]", "[A 6]", "[A 7]",
|
||||
"[A 8]", "[A 9]", "[A 10]", "[A 11]",
|
||||
"[A 12]", "[A 13]", "[A 14]", "[A 15]",
|
||||
"[A 16]", "[A 17]", "[A 18]", "[A 19]",
|
||||
"[A 20]", "[A 21]", "[A 22]", "[A 23]",
|
||||
"[A 24]", "[A 25]", "[A 26]", "[A 27]",
|
||||
"[A 28]", "[A 20]", "[A 30]", "[A 31]"
|
||||
},
|
||||
/* Context-Specific */
|
||||
{
|
||||
"[0]", "[1]", "[2]", "[3]", "[4]", "[5]", "[6]", "[7]",
|
||||
"[8]", "[9]", "[10]", "[11]", "[12]", "[13]", "[14]", "[15]",
|
||||
"[16]", "[17]", "[18]", "[19]", "[20]", "[21]", "[22]", "[23]",
|
||||
"[24]", "[25]", "[26]", "[27]", "[28]", "[20]", "[30]", "[31]"
|
||||
},
|
||||
/* Private */
|
||||
{
|
||||
"[P 0]", "[P 1]", "[P 2]", "[P 3]",
|
||||
"[P 4]", "[P 5]", "[P 6]", "[P 7]",
|
||||
"[P 8]", "[P 9]", "[P 10]", "[P 11]",
|
||||
"[P 12]", "[P 13]", "[P 14]", "[P 15]",
|
||||
"[P 16]", "[P 17]", "[P 18]", "[P 19]",
|
||||
"[P 20]", "[P 21]", "[P 22]", "[P 23]",
|
||||
"[P 24]", "[P 25]", "[P 26]", "[P 27]",
|
||||
"[P 28]", "[P 20]", "[P 30]", "[P 31]"
|
||||
}
|
||||
};
|
||||
|
||||
/* Converts a tag byte to string.
|
||||
*
|
||||
* @param [in] tag BER tag value to interpret.
|
||||
* @return String corresponding to tag.
|
||||
*/
|
||||
static const char* TagString(byte tag)
|
||||
{
|
||||
return tagString[tag >> 6][tag & ASN_TYPE_MASK];
|
||||
}
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
|
@ -5507,7 +5512,7 @@ int EncodeObjectId(const word16* in, word32 inSz, byte* out, word32* outSz)
|
|||
}
|
||||
#endif /* HAVE_OID_ENCODING */
|
||||
|
||||
#ifdef HAVE_OID_DECODING
|
||||
#if defined(HAVE_OID_DECODING) || defined(WOLFSSL_ASN_PRINT)
|
||||
/* Encode dotted form of OID into byte array version.
|
||||
*
|
||||
* @param [in] in Byte array containing OID.
|
||||
|
@ -5537,12 +5542,12 @@ int DecodeObjectId(const byte* in, word32 inSz, word16* out, word32* outSz)
|
|||
return BUFFER_E;
|
||||
}
|
||||
if (y == 0) {
|
||||
out[0] = (t / 40);
|
||||
out[1] = (t % 40);
|
||||
out[0] = (word16)(t / 40);
|
||||
out[1] = (word16)(t % 40);
|
||||
y = 2;
|
||||
}
|
||||
else {
|
||||
out[y++] = t;
|
||||
out[y++] = (word16)t;
|
||||
}
|
||||
t = 0; /* reset tmp */
|
||||
}
|
||||
|
@ -37020,6 +37025,803 @@ int wc_MIME_free_hdrs(MimeHdr* head)
|
|||
|
||||
#undef ERROR_OUT
|
||||
|
||||
|
||||
#ifdef WOLFSSL_ASN_PRINT
|
||||
|
||||
/*******************************************************************************
|
||||
* ASN.1 Parsing and Printing Implemenation
|
||||
******************************************************************************/
|
||||
|
||||
/* Initialize ASN.1 print options.
|
||||
*
|
||||
* @param [in, out] opts ASN.1 options for printing.
|
||||
* @return 0 on success.
|
||||
* @return BAD_FUNC_ARG when asn1 is NULL.
|
||||
*/
|
||||
int wc_Asn1PrintOptions_Init(Asn1PrintOptions* opts)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (opts == NULL) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
XMEMSET(opts, 0, sizeof(*opts));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set a print option into Asn1PrintOptions object.
|
||||
*
|
||||
* @param [in, out] opts ASN.1 options for printing.
|
||||
* @param [in] opt Option to set value of.
|
||||
* @param [in] val Value to set for option.
|
||||
* @return 0 on success.
|
||||
* @return BAD_FUNC_ARG when asn1 is NULL.
|
||||
* @return BAD_FUNC_ARG when val is out of range for option.
|
||||
*/
|
||||
int wc_Asn1PrintOptions_Set(Asn1PrintOptions* opts, enum Asn1PrintOpt opt,
|
||||
word32 val)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Validate parameters. */
|
||||
if (opts == NULL) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
switch (opt) {
|
||||
/* Offset into DER/BER data to start decoding from. */
|
||||
case ASN1_PRINT_OPT_OFFSET:
|
||||
opts->offset = val;
|
||||
break;
|
||||
/* Length of DER/BER encoding to parse. */
|
||||
case ASN1_PRINT_OPT_LENGTH:
|
||||
opts->length = val;
|
||||
break;
|
||||
/* Number of spaces to indent for each change in depth. */
|
||||
case ASN1_PRINT_OPT_INDENT:
|
||||
/* Only 4 bits available for value. */
|
||||
if (val >= (1 << 4)) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
opts->indent = val;
|
||||
}
|
||||
break;
|
||||
/* Draw branches instead of indenting. */
|
||||
case ASN1_PRINT_OPT_DRAW_BRANCH:
|
||||
/* Boolean value. */
|
||||
if (val > 1) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
opts->draw_branch = val;
|
||||
}
|
||||
break;
|
||||
/* Show raw data of primitive types as octets. */
|
||||
case ASN1_PRINT_OPT_SHOW_DATA:
|
||||
/* Boolean value. */
|
||||
if (val > 1) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
opts->show_data = val;
|
||||
}
|
||||
break;
|
||||
/* Show header data as octets. */
|
||||
case ASN1_PRINT_OPT_SHOW_HEADER_DATA:
|
||||
/* Boolean value. */
|
||||
if (val > 1) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
opts->show_header_data = val;
|
||||
}
|
||||
break;
|
||||
/* Show the wolfSSL OID value for OBJECT_ID. */
|
||||
case ASN1_PRINT_OPT_SHOW_OID:
|
||||
/* Boolean value. */
|
||||
if (val > 1) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
opts->show_oid = val;
|
||||
}
|
||||
break;
|
||||
/* Don't show text representations of primitive types. */
|
||||
case ASN1_PRINT_OPT_SHOW_NO_TEXT:
|
||||
/* Boolean value. */
|
||||
if (val > 1) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
opts->show_no_text = val;
|
||||
}
|
||||
break;
|
||||
/* Don't show dump text representations of primitive types. */
|
||||
case ASN1_PRINT_OPT_SHOW_NO_DUMP_TEXT:
|
||||
/* Boolean value. */
|
||||
if (val > 1) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
opts->show_no_dump_text = val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Initialize an ASN.1 parse object.
|
||||
*
|
||||
* @param [in, out] asn1 ASN.1 parse object.
|
||||
* @return 0 on success.
|
||||
* @return BAD_FUNC_ARG when asn1 is NULL.
|
||||
*/
|
||||
int wc_Asn1_Init(Asn1* asn1)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (asn1 == NULL) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
XMEMSET(asn1, 0, sizeof(*asn1));
|
||||
asn1->file = XBADFILE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set the file to use when printing.
|
||||
*
|
||||
* @param [in, out] asn1 ASN.1 parse object.
|
||||
* @param [in] file File to print to.
|
||||
* @return 0 on success.
|
||||
* @return BAD_FUNC_ARG when asn1 is NULL.
|
||||
* @return BAD_FUNC_ARG when file is XBADFILE.
|
||||
*/
|
||||
int wc_Asn1_SetFile(Asn1* asn1, XFILE file)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if ((asn1 == NULL) || (file == XBADFILE)) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
else {
|
||||
asn1->file = file;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Maximum OID dotted form size. */
|
||||
#define ASN1_OID_DOTTED_MAX_SZ 16
|
||||
|
||||
/* Print OID in dotted form or as hex bytes.
|
||||
*
|
||||
* @param [in] file File pointer to write to.
|
||||
* @param [in] oid OBJECT_ID data.
|
||||
* @param [in] oid_len Length of OBJECT_ID data.
|
||||
*/
|
||||
static void PrintObjectIdNum(XFILE file, unsigned char* oid, word32 len)
|
||||
{
|
||||
word16 dotted_nums[ASN1_OID_DOTTED_MAX_SZ];
|
||||
word32 num = ASN1_OID_DOTTED_MAX_SZ;
|
||||
word32 i;
|
||||
|
||||
/* Decode OBJECT_ID into dotted form array. */
|
||||
if (DecodeObjectId(oid, len, dotted_nums, &num) == 0) {
|
||||
/* Print out each number of dotted form. */
|
||||
for (i = 0; i < num; i++) {
|
||||
XFPRINTF(file, "%d", dotted_nums[i]);
|
||||
/* Add separetor. */
|
||||
if (i < num - 1) {
|
||||
XFPRINTF(file, ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Print out bytes as we couldn't decode. */
|
||||
for (i = 0; i < len; i++) {
|
||||
XFPRINTF(file, "%02x", oid[i]);
|
||||
/* Add separetor. */
|
||||
if (i < len - 1) {
|
||||
XFPRINTF(file, ":");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* OID value to name mapping. */
|
||||
typedef struct OidName {
|
||||
/* wolfSSL OID value. */
|
||||
word32 oid;
|
||||
/* Long name to print when OID seen. */
|
||||
const char* name;
|
||||
} OidName;
|
||||
|
||||
/* Extra OID to name mappings. */
|
||||
static const OidName extraOids[] = {
|
||||
{ 0x005c, "commonName" },
|
||||
{ 0x005d, "surname" },
|
||||
{ 0x005e, "serialNumber" },
|
||||
{ 0x005f, "countryName" },
|
||||
{ 0x0060, "localityName" },
|
||||
{ 0x0061, "stateOrProvinceName" },
|
||||
{ 0x0062, "streetAddress" },
|
||||
{ 0x0063, "organizationName" },
|
||||
{ 0x0064, "organizationUnitName" },
|
||||
{ 0x0065, "title" },
|
||||
{ 0x0086, "certificateExtension" },
|
||||
{ 0x028d, "emailAddress" },
|
||||
{ 0x0293, "challengePassword" },
|
||||
{ 0x029a, "extensionReq" },
|
||||
};
|
||||
/* Length of table of extra OID to name mappings. */
|
||||
#define EXTRA_OIDS_LEN ((int)(sizeof(extraOids) / sizeof(*extraOids)))
|
||||
|
||||
/* Convert OID value to long name.
|
||||
*
|
||||
* @param [in] oid OID value.
|
||||
* @param [out] name Long name for OID when known.
|
||||
* @return 1 when OID known.
|
||||
* @return 0 when OID not known.
|
||||
*/
|
||||
static int Oid2LongName(word32 oid, const char** name)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
/* Step through each entry in table. */
|
||||
for (i = 0; i < EXTRA_OIDS_LEN; i++) {
|
||||
if (extraOids[i].oid == oid) {
|
||||
/* Return the name associated with the OID value. */
|
||||
*name = extraOids[i].name;
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Print the text version of the OBJECT_ID.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
* @param [in] opts ASN.1 options for printing.
|
||||
*/
|
||||
static void PrintObjectIdText(Asn1* asn1, Asn1PrintOptions* opts)
|
||||
{
|
||||
word32 oid = (word32)-1;
|
||||
#if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA)
|
||||
word32 nid;
|
||||
#endif
|
||||
const char* ln = NULL;
|
||||
word32 i = 0;
|
||||
int known = 1;
|
||||
|
||||
/* Get the OID value for the OBJECT_ID. */
|
||||
GetObjectId(asn1->data + asn1->offset, &i, &oid, oidIgnoreType,
|
||||
asn1->item.len + 2);
|
||||
#if !defined(WOLFCRYPT_ONLY) && defined(OPENSSL_EXTRA)
|
||||
/* Lookup NID for OID value. */
|
||||
if ((nid = oid2nid(oid, oidIgnoreType)) != (word32)-1) {
|
||||
/* Lookup long name for NID. */
|
||||
ln = wolfSSL_OBJ_nid2ln(nid);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* Lookup long name for extra known OID values. */
|
||||
if (!Oid2LongName(oid, &ln)) {
|
||||
/* Unknown OID value. */
|
||||
ln = NULL;
|
||||
known = 0;
|
||||
}
|
||||
|
||||
XFPRINTF(asn1->file, ":");
|
||||
/* Show OID value if not known or asked to. */
|
||||
if ((!known) || opts->show_oid) {
|
||||
XFPRINTF(asn1->file, "(0x%x) ", oid);
|
||||
}
|
||||
if (ln != NULL) {
|
||||
/* Print long name. */
|
||||
XFPRINTF(asn1->file, "%s", ln);
|
||||
}
|
||||
else {
|
||||
/* Print out as numbers - either dotted or hex values. */
|
||||
PrintObjectIdNum(asn1->file, asn1->data + asn1->item.data_idx,
|
||||
asn1->item.len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print ASN.1 data as a character string.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
*/
|
||||
static void PrintText(Asn1* asn1)
|
||||
{
|
||||
word32 i;
|
||||
|
||||
XFPRINTF(asn1->file, ":");
|
||||
/* Print all data bytes as characters. */
|
||||
for (i = 0; i < asn1->item.len; i++) {
|
||||
XFPRINTF(asn1->file, "%c", asn1->data[asn1->item.data_idx + i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print data as a hex bytes.
|
||||
*
|
||||
* @param [in] file File pointer to write to.
|
||||
* @param [in] data Data to print.
|
||||
* @param [in] len Number of bytes to print.
|
||||
*/
|
||||
static void PrintHex(XFILE file, unsigned char* data, word32 len)
|
||||
{
|
||||
word32 i;
|
||||
|
||||
/* Print data bytes as hex numbers. */
|
||||
for (i = 0; i < len; i++) {
|
||||
XFPRINTF(file, "%02x", data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print ASN.1 data as a hex bytes.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
*/
|
||||
static void PrintHexText(Asn1* asn1)
|
||||
{
|
||||
XFPRINTF(asn1->file, ":");
|
||||
PrintHex(asn1->file, asn1->data + asn1->item.data_idx, asn1->item.len);
|
||||
}
|
||||
|
||||
/* Print ASN.1 BIT_STRING data as hex bytes noting special first byte.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
*/
|
||||
static void PrintBitStringText(Asn1* asn1)
|
||||
{
|
||||
if (asn1->item.len > 0) {
|
||||
XFPRINTF(asn1->file, ":[%02x]", asn1->data[asn1->item.data_idx]);
|
||||
PrintHex(asn1->file, asn1->data + asn1->item.data_idx + 1,
|
||||
asn1->item.len - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print ASN.1 BOOLEAN data as text with value.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
*/
|
||||
static void PrintBooleanText(Asn1* asn1)
|
||||
{
|
||||
/* Booleans should be 1 byte of data. */
|
||||
if (asn1->item.len == 1) {
|
||||
XFPRINTF(asn1->file, ":%s (%d)",
|
||||
(asn1->data[asn1->item.data_idx] == 0) ? "FALSE" : "TRUE",
|
||||
asn1->data[asn1->item.data_idx]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print ASN.1 data as single byte +/- number.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
*/
|
||||
static void PrintNumberText(Asn1* asn1)
|
||||
{
|
||||
/* Only supporting 1 byte of data for now. */
|
||||
if (asn1->item.len == 1) {
|
||||
int num = asn1->data[asn1->item.data_idx];
|
||||
|
||||
XFPRINTF(asn1->file, ":%d", num >= 0x80 ? num - 0x100 : num);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print ASN.1 data as a text based on the tag.
|
||||
*
|
||||
* TODO: handle more tags.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
* @param [in] opts ASN.1 options for printing.
|
||||
*/
|
||||
static void PrintAsn1Text(Asn1* asn1, Asn1PrintOptions* opts)
|
||||
{
|
||||
/* Get the long name for OBJECT_ID where possible. */
|
||||
if (asn1->item.tag == ASN_OBJECT_ID) {
|
||||
PrintObjectIdText(asn1, opts);
|
||||
}
|
||||
/* Data is an array of printable characters. */
|
||||
else if ((asn1->item.tag == ASN_UTF8STRING) ||
|
||||
(asn1->item.tag == ASN_IA5_STRING) ||
|
||||
(asn1->item.tag == ASN_PRINTABLE_STRING) ||
|
||||
(asn1->item.tag == ASN_T61STRING) ||
|
||||
(asn1->item.tag == ASN_BMPSTRING) ||
|
||||
(asn1->item.tag == ASN_UTC_TIME) ||
|
||||
(asn1->item.tag == ASN_GENERALIZED_TIME) ||
|
||||
(asn1->item.tag == ASN_UNIVERSALSTRING) ||
|
||||
(asn1->item.tag == ASN_OBJECT_DESC) ||
|
||||
(asn1->item.tag == ASN_CHARACTER_STRING)) {
|
||||
PrintText(asn1);
|
||||
}
|
||||
/* Show TRUE and FALSE with number. */
|
||||
else if (asn1->item.tag == ASN_BOOLEAN) {
|
||||
PrintBooleanText(asn1);
|
||||
}
|
||||
/* Show number. */
|
||||
else if (asn1->item.tag == ASN_ENUMERATED) {
|
||||
PrintNumberText(asn1);
|
||||
}
|
||||
/* Dumping potentially long string of hex digites. */
|
||||
else if (!opts->show_no_dump_text) {
|
||||
/* Dump all bytes. */
|
||||
if ((asn1->item.tag == ASN_INTEGER) ||
|
||||
(asn1->item.tag == ASN_OCTET_STRING) ||
|
||||
((asn1->item.tag > ASN_APPLICATION) && (asn1->item.cons))) {
|
||||
PrintHexText(asn1);
|
||||
}
|
||||
/* First byte is number of unused bits in last byte.
|
||||
* Print first specially and dump rest of the bytes. */
|
||||
else if (asn1->item.tag == ASN_BIT_STRING) {
|
||||
PrintBitStringText(asn1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define HexToChar(n) ((((n) >= 32) && ((n) < 127)) ? (n) : '.')
|
||||
|
||||
/* Dump data as hex bytes.
|
||||
*
|
||||
* @param [in] file File pointer to write to.
|
||||
* @param [in] data Data to print.
|
||||
* @param [in] len Number of bytes to print.
|
||||
*/
|
||||
static void DumpData(XFILE file, unsigned char* data, word32 len)
|
||||
{
|
||||
word32 i;
|
||||
word32 j;
|
||||
|
||||
for (i = 0; i < len; i += j) {
|
||||
/* Print offset. */
|
||||
XFPRINTF(file, " %04x:", i);
|
||||
for (j = 0; (j < 16) && (i + j < len); j++) {
|
||||
/* Print byte as hex number. */
|
||||
XFPRINTF(file, "%s%02x", (j == 8) ? " " : " ", data[i + j]);
|
||||
}
|
||||
/* Print spaces between hex and characters. */
|
||||
XFPRINTF(file, " %*s", (16 - j) * 3 + ((j < 8) ? 1 : 0), "");
|
||||
for (j = 0; (j < 16) && (i + j < len); j++) {
|
||||
/* Print byte as hex number. */
|
||||
XFPRINTF(file, "%c", HexToChar(data[i + j]));
|
||||
}
|
||||
XFPRINTF(file, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Update current depth based on the current position.
|
||||
*
|
||||
* @param [in, out] asn1 ASN.1 parse object.
|
||||
*/
|
||||
static void UpdateDepth(Asn1* asn1)
|
||||
{
|
||||
/* If current index is greater than or equal end index then it is done. */
|
||||
while ((asn1->depth > 0) &&
|
||||
(asn1->end_idx[asn1->depth-1] <= asn1->curr)) {
|
||||
/* Move up a depth. */
|
||||
asn1->depth--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check validity of end index of constructed ASN.1 items.
|
||||
*
|
||||
* @param [in, out] asn1 ASN.1 parse object.
|
||||
* @return 0 on success.
|
||||
* @return ASN_DEPTH_E when end offset invalid.
|
||||
*/
|
||||
static int CheckDepth(Asn1* asn1)
|
||||
{
|
||||
int ret = 0;
|
||||
int i;
|
||||
word32 curr_end = asn1->curr + asn1->item.len;
|
||||
|
||||
for (i = 0; (ret == 0) && (i < asn1->depth); i++) {
|
||||
/* Each end index must be at least as large as the current one. */
|
||||
if (asn1->end_idx[i] < asn1->end_idx[asn1->depth]) {
|
||||
ret = ASN_DEPTH_E;
|
||||
}
|
||||
/* Each end index must be at least as large as current index. */
|
||||
if (asn1->end_idx[i] < curr_end) {
|
||||
ret = ASN_DEPTH_E;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Draw branching based on depth for an ASN.1 item.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
*/
|
||||
static void DrawBranch(Asn1* asn1)
|
||||
{
|
||||
int i;
|
||||
word32 end = asn1->curr + asn1->item.len;
|
||||
|
||||
/* Write out the character for all depths but current. */
|
||||
for (i = 0; i < asn1->depth; i++) {
|
||||
if (asn1->item.cons || (end < asn1->end_idx[i])) {
|
||||
if (i < asn1->depth - 1) {
|
||||
/* Constructed or not end index and not current depth: | */
|
||||
XFPRINTF(asn1->file, "\xe2\x94\x82");
|
||||
}
|
||||
else {
|
||||
/* Constructed or not end index and current depth: |- */
|
||||
XFPRINTF(asn1->file, "\xe2\x94\x9c");
|
||||
}
|
||||
}
|
||||
else if ((i > 1) && (end >= asn1->end_idx[i-1])) {
|
||||
/* End index for previous: _|_ (in top half) */
|
||||
XFPRINTF(asn1->file, "\xe2\x94\xb4");
|
||||
}
|
||||
else {
|
||||
/* End index but not for previous: L (in top half) */
|
||||
XFPRINTF(asn1->file, "\xe2\x94\x94");
|
||||
}
|
||||
}
|
||||
/* Prefix to tag name. */
|
||||
if (asn1->item.cons) {
|
||||
if (asn1->depth > 0) {
|
||||
/* Have other line to connect to: T (in bottom half) */
|
||||
XFPRINTF(asn1->file, "\xe2\x94\xac");
|
||||
}
|
||||
else {
|
||||
/* Have no other line to connect to: r */
|
||||
XFPRINTF(asn1->file, "\xe2\x94\x8c");
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* In a sequence: - */
|
||||
XFPRINTF(asn1->file, "\xe2\x94\x80");
|
||||
}
|
||||
}
|
||||
|
||||
/* Print data as hex bytes separated by space.
|
||||
*
|
||||
* @param [in] file File pointer to write to.
|
||||
* @param [in] data Data to print.
|
||||
* @param [in] len Number of bytes to print.
|
||||
*/
|
||||
static void PrintHexBytes(XFILE file, unsigned char* data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
XFPRINTF(file, " %02x", data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump header data.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
* @param [in] opts ASN.1 options for printing.
|
||||
*/
|
||||
static void DumpHeader(Asn1* asn1, Asn1PrintOptions* opts)
|
||||
{
|
||||
/* Put on same line when not showing data too and not showing text data. */
|
||||
if ((!opts->show_data) && opts->show_no_text) {
|
||||
XFPRINTF(asn1->file, "%10s %02x", "", asn1->item.tag);
|
||||
}
|
||||
else {
|
||||
/* Align with start of data. */
|
||||
XFPRINTF(asn1->file, "\n%12s %02x", "", asn1->item.tag);
|
||||
}
|
||||
/* Print the header bytes as hex bytes separated by a space. */
|
||||
PrintHexBytes(asn1->file, asn1->data + asn1->offset + 1,
|
||||
asn1->curr - (asn1->offset + 1));
|
||||
}
|
||||
|
||||
/* Print ASN.1 item info based on header and indeces.
|
||||
*
|
||||
* @param [in] asn1 ASN.1 parse object.
|
||||
* @param [in] opts ASN.1 options for printing.
|
||||
*/
|
||||
static void PrintInfo(Asn1* asn1, Asn1PrintOptions* opts)
|
||||
{
|
||||
/* Print offset of this ASN.1 item. */
|
||||
XFPRINTF(asn1->file, "%4d: ", asn1->offset);
|
||||
/* Print length of header. */
|
||||
XFPRINTF(asn1->file, "%1d ", asn1->curr - asn1->offset);
|
||||
/* Print data length. */
|
||||
XFPRINTF(asn1->file, "%c%4d%c", asn1->item.cons ? '[' : '+', asn1->item.len,
|
||||
asn1->item.cons ? ']' : ' ');
|
||||
/* Print depth. */
|
||||
XFPRINTF(asn1->file, " %s(%d)", (asn1->depth < 10) ? " " : "", asn1->depth);
|
||||
if (!opts->draw_branch) {
|
||||
/* Indent to depth as required. */
|
||||
XFPRINTF(asn1->file, "%*s ", asn1->depth * opts->indent, "");
|
||||
if (!opts->indent) {
|
||||
/* Indicate constructed if no indent. */
|
||||
XFPRINTF(asn1->file, "%c", asn1->item.cons ? '+' : ' ');
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Draw branch structure for ASN.1 item. */
|
||||
XFPRINTF(asn1->file, " ");
|
||||
DrawBranch(asn1);
|
||||
}
|
||||
/* Print tag name. */
|
||||
XFPRINTF(asn1->file, "%-16s", TagString(asn1->item.tag));
|
||||
}
|
||||
|
||||
/* Expecting tag part of ASN.1 item. */
|
||||
#define ASN_PART_TAG 0
|
||||
/* Expecting length part of ASN.1 item. */
|
||||
#define ASN_PART_LENGTH 1
|
||||
/* Expecting data part of ASN.1 item. */
|
||||
#define ASN_PART_DATA 2
|
||||
|
||||
/* Print next ASN.1 item.
|
||||
*
|
||||
* @param [in, out] asn1 ASN.1 parse object.
|
||||
* @param [in] opts ASN.1 print options.
|
||||
* @return 0 on success.
|
||||
* @return BAD_FUNC_ARG when asn1 or opts is NULL.
|
||||
* @return ASN_LEN_E when ASN.1 item's length too long.
|
||||
* @return ASN_DEPTH_E when end offset invalid.
|
||||
*/
|
||||
static int wc_Asn1_Print(Asn1* asn1, Asn1PrintOptions* opts)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if ((asn1 == NULL) || (opts == NULL)) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* Process tag. */
|
||||
if (asn1->part == ASN_PART_TAG) {
|
||||
/* Recalculate which depth we are at. */
|
||||
UpdateDepth(asn1);
|
||||
/* Get tag. */
|
||||
asn1->item.tag = asn1->data[asn1->curr] & ~ASN_CONSTRUCTED;
|
||||
/* Store whether tag indicates constructed. */
|
||||
asn1->item.cons = (asn1->data[asn1->curr] & ASN_CONSTRUCTED) ==
|
||||
ASN_CONSTRUCTED;
|
||||
/* Start of ASN.1 item is current index. */
|
||||
asn1->offset = asn1->curr;
|
||||
/* Step over tag. */
|
||||
asn1->curr++;
|
||||
/* Next part is length. */
|
||||
asn1->part = ASN_PART_LENGTH;
|
||||
}
|
||||
/* Process length. */
|
||||
if (asn1->part == ASN_PART_LENGTH) {
|
||||
int len;
|
||||
|
||||
/* Decode length and step over it. */
|
||||
if (GetLength(asn1->data, &asn1->curr, &len, asn1->max) < 0) {
|
||||
ret = ASN_LEN_E;
|
||||
}
|
||||
else {
|
||||
/* Store ASN.1 item data offset. */
|
||||
asn1->item.data_idx = asn1->curr;
|
||||
/* Store ASN.1 item data length. */
|
||||
asn1->item.len = len;
|
||||
|
||||
/* Print info about ASN.1 item. */
|
||||
PrintInfo(asn1, opts);
|
||||
|
||||
if (!asn1->item.cons) {
|
||||
/* Move on to print data. */
|
||||
asn1->part = ASN_PART_DATA;
|
||||
}
|
||||
else {
|
||||
/* Print header now if not printing data. */
|
||||
if (opts->show_header_data) {
|
||||
DumpHeader(asn1, opts);
|
||||
}
|
||||
XFPRINTF(asn1->file, "\n");
|
||||
/* Record end offset for this depth. */
|
||||
asn1->end_idx[asn1->depth++] = asn1->curr + asn1->item.len;
|
||||
/* Done with this ASN.1 item. */
|
||||
asn1->part = ASN_PART_TAG;
|
||||
}
|
||||
/* Check end indeces are valid. */
|
||||
ret = CheckDepth(asn1);
|
||||
}
|
||||
}
|
||||
/* Process data. */
|
||||
if ((ret == 0) && (asn1->part == ASN_PART_DATA)) {
|
||||
if (!opts->show_no_text) {
|
||||
/* Print text representation of data. */
|
||||
PrintAsn1Text(asn1, opts);
|
||||
}
|
||||
if (opts->show_header_data) {
|
||||
/* Dump header bytes. */
|
||||
DumpHeader(asn1, opts);
|
||||
}
|
||||
XFPRINTF(asn1->file, "\n");
|
||||
if (opts->show_data) {
|
||||
/* Dump data bytes. */
|
||||
DumpData(asn1->file, asn1->data + asn1->item.data_idx,
|
||||
asn1->item.len);
|
||||
}
|
||||
/* Step past data to next ASN.1 item. */
|
||||
asn1->curr += asn1->item.len;
|
||||
/* Update the depth based on end indeces. */
|
||||
UpdateDepth(asn1);
|
||||
/* Done with this ASN.1 item. */
|
||||
asn1->part = ASN_PART_TAG;
|
||||
}
|
||||
|
||||
/* Make ASN.1 item printing go out. */
|
||||
fflush(asn1->file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Print all ASN.1 items.
|
||||
*
|
||||
* @param [in, out] asn1 ASN.1 parse object.
|
||||
* @param [in] opts ASN.1 print options.
|
||||
* @param [in] data BER/DER data to print.
|
||||
* @param [in] len Length of data to print in bytes.
|
||||
* @return 0 on success.
|
||||
* @return BAD_FUNC_ARG when asn1 or opts is NULL.
|
||||
* @return ASN_LEN_E when ASN.1 item's length too long.
|
||||
* @return ASN_DEPTH_E when end offset invalid.
|
||||
* @return ASN_PARSE_E when not all of an ASN.1 item parsed.
|
||||
*/
|
||||
int wc_Asn1_PrintAll(Asn1* asn1, Asn1PrintOptions* opts, unsigned char* data,
|
||||
word32 len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (asn1 == NULL) {
|
||||
ret = BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
/* Initialize start position. */
|
||||
asn1->curr = 0;
|
||||
/* Start parsing at tag. */
|
||||
asn1->part = ASN_PART_TAG;
|
||||
/* Start depth at 0. */
|
||||
asn1->depth = 0;
|
||||
|
||||
/* Store the starting point of the data to parse. */
|
||||
asn1->data = data + opts->offset;
|
||||
if (opts->length > 0) {
|
||||
/* Use user specified maximum length. */
|
||||
asn1->max = opts->length;
|
||||
}
|
||||
else {
|
||||
/* Maximum length is up to end from offset. */
|
||||
asn1->max = len - opts->offset;
|
||||
}
|
||||
|
||||
/* Keep going while no error and have data to parse. */
|
||||
while ((ret == 0) && (asn1->curr < asn1->max)) {
|
||||
/* Print an ASN.1 item. */
|
||||
ret = wc_Asn1_Print(asn1, opts);
|
||||
}
|
||||
}
|
||||
if ((ret == 0) && (asn1->part != ASN_PART_TAG)) {
|
||||
/* Stopped before finishing ASN.1 item. */
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
if ((ret == 0) && (asn1->depth != 0)) {
|
||||
/* Stopped without seeing all items in a constructed item. */
|
||||
ret = ASN_DEPTH_E;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* WOLFSSL_ASN_PRINT */
|
||||
#endif /* !NO_ASN */
|
||||
|
||||
#ifdef WOLFSSL_SEP
|
||||
|
|
|
@ -583,6 +583,12 @@ const char* wc_GetErrorString(int error)
|
|||
case ENTROPY_APT_E:
|
||||
return "Entropy Adaptive Proportion Test failed";
|
||||
|
||||
case ASN_DEPTH_E:
|
||||
return "Invalid ASN.1 - depth check";
|
||||
|
||||
case ASN_LEN_E:
|
||||
return "ASN.1 length invalid";
|
||||
|
||||
default:
|
||||
return "unknown error number";
|
||||
|
||||
|
|
|
@ -95,16 +95,27 @@ enum ASN_Tags {
|
|||
ASN_OCTET_STRING = 0x04,
|
||||
ASN_TAG_NULL = 0x05,
|
||||
ASN_OBJECT_ID = 0x06,
|
||||
ASN_OBJECT_DESC = 0x07,
|
||||
ASN_INSTANCE_OF = 0x08,
|
||||
ASN_REAL = 0x09,
|
||||
ASN_ENUMERATED = 0x0a,
|
||||
ASN_EMBEDDED_PDV = 0x0b,
|
||||
ASN_UTF8STRING = 0x0c,
|
||||
ASN_RELATIVE_OID = 0x0d,
|
||||
ASN_SEQUENCE = 0x10,
|
||||
ASN_SET = 0x11,
|
||||
ASN_NUMERICSTRING = 0x12,
|
||||
ASN_PRINTABLE_STRING = 0x13,
|
||||
ASN_T61STRING = 0x14,
|
||||
ASN_VIDEOTEXSTRING = 0x15,
|
||||
ASN_IA5_STRING = 0x16,
|
||||
ASN_UTC_TIME = 0x17,
|
||||
ASN_GENERALIZED_TIME = 0x18,
|
||||
ASN_GRAPHICSTRING = 0x19,
|
||||
ASN_ISO646STRING = 0x1a,
|
||||
ASN_GENERALSTRING = 0x1b,
|
||||
ASN_UNIVERSALSTRING = 0x1c,
|
||||
ASN_CHARACTER_STRING = 0x1d,
|
||||
ASN_BMPSTRING = 0x1e,
|
||||
ASN_TYPE_MASK = 0x1f,
|
||||
|
||||
|
@ -2153,7 +2164,7 @@ WOLFSSL_LOCAL int GetInt(mp_int* mpi, const byte* input, word32* inOutIdx,
|
|||
WOLFSSL_LOCAL int EncodeObjectId(const word16* in, word32 inSz,
|
||||
byte* out, word32* outSz);
|
||||
#endif
|
||||
#ifdef HAVE_OID_DECODING
|
||||
#if defined(HAVE_OID_DECODING) || defined(WOLFSSL_ASN_PRINT)
|
||||
WOLFSSL_LOCAL int DecodeObjectId(const byte* in, word32 inSz,
|
||||
word16* out, word32* outSz);
|
||||
#endif
|
||||
|
|
|
@ -914,4 +914,104 @@ WOLFSSL_API int wc_GetFASCNFromCert(struct DecodedCert* cert,
|
|||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#if !defined(XFPRINTF) || defined(NO_FILESYSTEM) || \
|
||||
defined(NO_STDIO_FILESYSTEM) && defined(WOLFSSL_ASN_PRINT)
|
||||
#undef WOLFSSL_ASN_PRINT
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_ASN_PRINT
|
||||
|
||||
enum Asn1PrintOpt {
|
||||
/* Offset into DER/BER data to start decoding from. */
|
||||
ASN1_PRINT_OPT_OFFSET,
|
||||
/* Length of DER/BER encoding to parse. */
|
||||
ASN1_PRINT_OPT_LENGTH,
|
||||
/* Number of spaces to indent for each change in depth. */
|
||||
ASN1_PRINT_OPT_INDENT,
|
||||
/* Draw branches instead of indenting. */
|
||||
ASN1_PRINT_OPT_DRAW_BRANCH,
|
||||
/* Show raw data of primitive types as octets. */
|
||||
ASN1_PRINT_OPT_SHOW_DATA,
|
||||
/* Show header data as octets. */
|
||||
ASN1_PRINT_OPT_SHOW_HEADER_DATA,
|
||||
/* Show the wolfSSL OID value for OBJECT_ID. */
|
||||
ASN1_PRINT_OPT_SHOW_OID,
|
||||
/* Don't show text representations of primitive types. */
|
||||
ASN1_PRINT_OPT_SHOW_NO_TEXT,
|
||||
/* Don't show dump text representations of primitive types. */
|
||||
ASN1_PRINT_OPT_SHOW_NO_DUMP_TEXT,
|
||||
};
|
||||
|
||||
/* ASN.1 print options. */
|
||||
typedef struct Asn1PrintOptions {
|
||||
/* Offset into DER/BER encoding to start parsing from. */
|
||||
word32 offset;
|
||||
/* Length of DER/BER encoding to parse. */
|
||||
word32 length;
|
||||
/* Number of spaces to indent for each change in depth. */
|
||||
int indent:4;
|
||||
/* Draw branches instead of indenting. */
|
||||
int draw_branch:1;
|
||||
/* Show raw data of primitive types as octets. */
|
||||
int show_data:1;
|
||||
/* Show header data as octets. */
|
||||
int show_header_data:1;
|
||||
/* Show the wolfSSL OID value for OBJECT_ID. */
|
||||
int show_oid:1;
|
||||
/* Don't show text representations of primitive types. */
|
||||
int show_no_text:1;
|
||||
/* Don't show dump text representations of primitive types. */
|
||||
int show_no_dump_text:1;
|
||||
} Asn1PrintOptions;
|
||||
|
||||
/* ASN.1 item data. */
|
||||
typedef struct Asn1Item {
|
||||
/* Tag of current item. */
|
||||
unsigned char tag;
|
||||
/* Whether current item is constructed. */
|
||||
unsigned char cons;
|
||||
/* Length of data in current ASN.1 item. */
|
||||
word32 len;
|
||||
/* Index into data of ASN.1 item data. */
|
||||
word32 data_idx;
|
||||
} Asn1Item;
|
||||
|
||||
/* Maximum supported depth of ASN.1 items. */
|
||||
#define ASN_MAX_DEPTH 16
|
||||
|
||||
/* ASN.1 parsing state. */
|
||||
typedef struct Asn1 {
|
||||
/* ASN.1 item data. */
|
||||
Asn1Item item;
|
||||
/* Current depth of ASN.1 item. */
|
||||
unsigned char depth;
|
||||
/* End indeces of ASN.1 items at different depths. */
|
||||
word32 end_idx[ASN_MAX_DEPTH];
|
||||
|
||||
/* Buffer to print. */
|
||||
unsigned char* data;
|
||||
/* Maximum number of bytes to process. */
|
||||
word32 max;
|
||||
/* Starting offset of current ASN.1 item. */
|
||||
word32 offset;
|
||||
/* Current offset into ASN.1 data. */
|
||||
word32 curr;
|
||||
/* Next part of ASN.1 item expected. */
|
||||
unsigned char part;
|
||||
|
||||
/* File pointer to print to. */
|
||||
XFILE file;
|
||||
} Asn1;
|
||||
|
||||
WOLFSSL_API int wc_Asn1PrintOptions_Init(Asn1PrintOptions* opts);
|
||||
WOLFSSL_API int wc_Asn1PrintOptions_Set(Asn1PrintOptions* opts,
|
||||
enum Asn1PrintOpt opt, word32 val);
|
||||
|
||||
WOLFSSL_API int wc_Asn1_Init(Asn1* asn1);
|
||||
WOLFSSL_API int wc_Asn1_SetFile(Asn1* asn1, XFILE file);
|
||||
WOLFSSL_API int wc_Asn1_PrintAll(Asn1* asn1, Asn1PrintOptions* opts,
|
||||
unsigned char* data, word32 len);
|
||||
|
||||
#endif /* WOLFSSL_ASN_PRINT */
|
||||
|
||||
#endif /* WOLF_CRYPT_ASN_PUBLIC_H */
|
||||
|
|
|
@ -257,7 +257,10 @@ enum {
|
|||
ENTROPY_RT_E = -294, /* Entropy Repetition Test failed */
|
||||
ENTROPY_APT_E = -295, /* Entropy Adaptive Proportion Test failed */
|
||||
|
||||
WC_LAST_E = -295, /* Update this to indicate last error */
|
||||
ASN_DEPTH_E = -296, /* Invalid ASN.1 - depth check */
|
||||
ASN_LEN_E = -297, /* ASN.1 length invalid */
|
||||
|
||||
WC_LAST_E = -297, /* Update this to indicate last error */
|
||||
MIN_CODE_E = -300 /* errors -101 - -299 */
|
||||
|
||||
/* add new companion error id strings for any new error codes
|
||||
|
|
Loading…
Reference in New Issue