add original 3.5.0 and replace with 3.1.7. NOTE:- This commit will NOT COMPILE. (#15)
Reviewed-on: http://13.234.246.121:3000/Neominds/ossl35vx69/pulls/15 Co-authored-by: siddhant <siddhant.singh@neominds.in> Co-committed-by: siddhant <siddhant.singh@neominds.in>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is dual-licensed and is also available under the following
|
||||
* terms:
|
||||
*
|
||||
* Copyright (c) 2004, Richard Levitte <richard@levitte.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LPDIR_H
|
||||
# include "LPdir.h"
|
||||
#endif
|
||||
|
||||
struct LP_dir_context_st {
|
||||
void *dummy;
|
||||
};
|
||||
const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int LP_find_file_end(LP_DIR_CTX **ctx)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright 2004-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is dual-licensed and is also available under the following
|
||||
* terms:
|
||||
*
|
||||
* Copyright (c) 2004, 2018, Richard Levitte <richard@levitte.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#ifndef LPDIR_H
|
||||
# include "LPdir.h"
|
||||
#endif
|
||||
#ifdef __VMS
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The POSIX macro for the maximum number of characters in a file path is
|
||||
* NAME_MAX. However, some operating systems use PATH_MAX instead.
|
||||
* Therefore, it seems natural to first check for PATH_MAX and use that, and
|
||||
* if it doesn't exist, use NAME_MAX.
|
||||
*/
|
||||
#if defined(PATH_MAX)
|
||||
# define LP_ENTRY_SIZE PATH_MAX
|
||||
#elif defined(NAME_MAX)
|
||||
# define LP_ENTRY_SIZE NAME_MAX
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Of course, there's the possibility that neither PATH_MAX nor NAME_MAX
|
||||
* exist. It's also possible that NAME_MAX exists but is define to a very
|
||||
* small value (HP-UX offers 14), so we need to check if we got a result, and
|
||||
* if it meets a minimum standard, and create or change it if not.
|
||||
*/
|
||||
#if !defined(LP_ENTRY_SIZE) || LP_ENTRY_SIZE<255
|
||||
# undef LP_ENTRY_SIZE
|
||||
# define LP_ENTRY_SIZE 255
|
||||
#endif
|
||||
|
||||
struct LP_dir_context_st {
|
||||
DIR *dir;
|
||||
char entry_name[LP_ENTRY_SIZE + 1];
|
||||
#ifdef __VMS
|
||||
int expect_file_generations;
|
||||
char previous_entry_name[LP_ENTRY_SIZE + 1];
|
||||
#endif
|
||||
};
|
||||
|
||||
const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
|
||||
{
|
||||
struct dirent *direntry = NULL;
|
||||
|
||||
if (ctx == NULL || directory == NULL) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (*ctx == NULL) {
|
||||
*ctx = malloc(sizeof(**ctx));
|
||||
if (*ctx == NULL) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
memset(*ctx, 0, sizeof(**ctx));
|
||||
|
||||
#ifdef __VMS
|
||||
{
|
||||
char c = directory[strlen(directory) - 1];
|
||||
|
||||
if (c == ']' || c == '>' || c == ':')
|
||||
(*ctx)->expect_file_generations = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
(*ctx)->dir = opendir(directory);
|
||||
if ((*ctx)->dir == NULL) {
|
||||
int save_errno = errno; /* Probably not needed, but I'm paranoid */
|
||||
free(*ctx);
|
||||
*ctx = NULL;
|
||||
errno = save_errno;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __VMS
|
||||
strncpy((*ctx)->previous_entry_name, (*ctx)->entry_name,
|
||||
sizeof((*ctx)->previous_entry_name));
|
||||
|
||||
again:
|
||||
#endif
|
||||
|
||||
direntry = readdir((*ctx)->dir);
|
||||
if (direntry == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
OPENSSL_strlcpy((*ctx)->entry_name, direntry->d_name,
|
||||
sizeof((*ctx)->entry_name));
|
||||
#ifdef __VMS
|
||||
if ((*ctx)->expect_file_generations) {
|
||||
char *p = (*ctx)->entry_name + strlen((*ctx)->entry_name);
|
||||
|
||||
while (p > (*ctx)->entry_name && isdigit((unsigned char)p[-1]))
|
||||
p--;
|
||||
if (p > (*ctx)->entry_name && p[-1] == ';')
|
||||
p[-1] = '\0';
|
||||
if (OPENSSL_strcasecmp((*ctx)->entry_name,
|
||||
(*ctx)->previous_entry_name) == 0)
|
||||
goto again;
|
||||
}
|
||||
#endif
|
||||
return (*ctx)->entry_name;
|
||||
}
|
||||
|
||||
int LP_find_file_end(LP_DIR_CTX **ctx)
|
||||
{
|
||||
if (ctx != NULL && *ctx != NULL) {
|
||||
int ret = closedir((*ctx)->dir);
|
||||
|
||||
free(*ctx);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
return 1;
|
||||
case -1:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is dual-licensed and is also available under the following
|
||||
* terms:
|
||||
*
|
||||
* Copyright (c) 2004, Richard Levitte <richard@levitte.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <descrip.h>
|
||||
#include <namdef.h>
|
||||
#include <rmsdef.h>
|
||||
#include <libfildef.h>
|
||||
#include <lib$routines.h>
|
||||
#include <strdef.h>
|
||||
#include <str$routines.h>
|
||||
#include <stsdef.h>
|
||||
#ifndef LPDIR_H
|
||||
# include "LPdir.h"
|
||||
#endif
|
||||
#include "vms_rms.h"
|
||||
|
||||
/* Some compiler options hide EVMSERR. */
|
||||
#ifndef EVMSERR
|
||||
# define EVMSERR 65535 /* error for non-translatable VMS errors */
|
||||
#endif
|
||||
|
||||
struct LP_dir_context_st {
|
||||
unsigned long VMS_context;
|
||||
char filespec[NAMX_MAXRSS + 1];
|
||||
char result[NAMX_MAXRSS + 1];
|
||||
struct dsc$descriptor_d filespec_dsc;
|
||||
struct dsc$descriptor_d result_dsc;
|
||||
};
|
||||
|
||||
const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
|
||||
{
|
||||
int status;
|
||||
char *p, *r;
|
||||
size_t l;
|
||||
unsigned long flags = 0;
|
||||
|
||||
/* Arrange 32-bit pointer to (copied) string storage, if needed. */
|
||||
#if __INITIAL_POINTER_SIZE == 64
|
||||
# pragma pointer_size save
|
||||
# pragma pointer_size 32
|
||||
char *ctx_filespec_32p;
|
||||
# pragma pointer_size restore
|
||||
char ctx_filespec_32[NAMX_MAXRSS + 1];
|
||||
#endif /* __INITIAL_POINTER_SIZE == 64 */
|
||||
|
||||
#ifdef NAML$C_MAXRSS
|
||||
flags |= LIB$M_FIL_LONG_NAMES;
|
||||
#endif
|
||||
|
||||
if (ctx == NULL || directory == NULL) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (*ctx == NULL) {
|
||||
size_t filespeclen = strlen(directory);
|
||||
char *filespec = NULL;
|
||||
|
||||
if (filespeclen == 0) {
|
||||
errno = ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* MUST be a VMS directory specification! Let's estimate if it is. */
|
||||
if (directory[filespeclen - 1] != ']'
|
||||
&& directory[filespeclen - 1] != '>'
|
||||
&& directory[filespeclen - 1] != ':') {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
filespeclen += 4; /* "*.*;" */
|
||||
|
||||
if (filespeclen > NAMX_MAXRSS) {
|
||||
errno = ENAMETOOLONG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ctx = malloc(sizeof(**ctx));
|
||||
if (*ctx == NULL) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
memset(*ctx, 0, sizeof(**ctx));
|
||||
|
||||
strcpy((*ctx)->filespec, directory);
|
||||
strcat((*ctx)->filespec, "*.*;");
|
||||
|
||||
/* Arrange 32-bit pointer to (copied) string storage, if needed. */
|
||||
#if __INITIAL_POINTER_SIZE == 64
|
||||
# define CTX_FILESPEC ctx_filespec_32p
|
||||
/* Copy the file name to storage with a 32-bit pointer. */
|
||||
ctx_filespec_32p = ctx_filespec_32;
|
||||
strcpy(ctx_filespec_32p, (*ctx)->filespec);
|
||||
#else /* __INITIAL_POINTER_SIZE == 64 */
|
||||
# define CTX_FILESPEC (*ctx)->filespec
|
||||
#endif /* __INITIAL_POINTER_SIZE == 64 [else] */
|
||||
|
||||
(*ctx)->filespec_dsc.dsc$w_length = filespeclen;
|
||||
(*ctx)->filespec_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
|
||||
(*ctx)->filespec_dsc.dsc$b_class = DSC$K_CLASS_S;
|
||||
(*ctx)->filespec_dsc.dsc$a_pointer = CTX_FILESPEC;
|
||||
}
|
||||
|
||||
(*ctx)->result_dsc.dsc$w_length = 0;
|
||||
(*ctx)->result_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
|
||||
(*ctx)->result_dsc.dsc$b_class = DSC$K_CLASS_D;
|
||||
(*ctx)->result_dsc.dsc$a_pointer = 0;
|
||||
|
||||
status = lib$find_file(&(*ctx)->filespec_dsc, &(*ctx)->result_dsc,
|
||||
&(*ctx)->VMS_context, 0, 0, 0, &flags);
|
||||
|
||||
if (status == RMS$_NMF) {
|
||||
errno = 0;
|
||||
vaxc$errno = status;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!$VMS_STATUS_SUCCESS(status)) {
|
||||
errno = EVMSERR;
|
||||
vaxc$errno = status;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quick, cheap and dirty way to discard any device and directory, since
|
||||
* we only want file names
|
||||
*/
|
||||
l = (*ctx)->result_dsc.dsc$w_length;
|
||||
p = (*ctx)->result_dsc.dsc$a_pointer;
|
||||
r = p;
|
||||
for (; *p; p++) {
|
||||
if (*p == '^' && p[1] != '\0') { /* Take care of ODS-5 escapes */
|
||||
p++;
|
||||
} else if (*p == ':' || *p == '>' || *p == ']') {
|
||||
l -= p + 1 - r;
|
||||
r = p + 1;
|
||||
} else if (*p == ';') {
|
||||
l = p - r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strncpy((*ctx)->result, r, l);
|
||||
(*ctx)->result[l] = '\0';
|
||||
str$free1_dx(&(*ctx)->result_dsc);
|
||||
|
||||
return (*ctx)->result;
|
||||
}
|
||||
|
||||
int LP_find_file_end(LP_DIR_CTX **ctx)
|
||||
{
|
||||
if (ctx != NULL && *ctx != NULL) {
|
||||
int status = lib$find_file_end(&(*ctx)->VMS_context);
|
||||
|
||||
free(*ctx);
|
||||
|
||||
if (!$VMS_STATUS_SUCCESS(status)) {
|
||||
errno = EVMSERR;
|
||||
vaxc$errno = status;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is dual-licensed and is also available under the following
|
||||
* terms:
|
||||
*
|
||||
* Copyright (c) 2004, Richard Levitte <richard@levitte.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include "internal/numbers.h"
|
||||
#ifndef LPDIR_H
|
||||
# include "LPdir.h"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We're most likely overcautious here, but let's reserve for broken WinCE
|
||||
* headers and explicitly opt for UNICODE call. Keep in mind that our WinCE
|
||||
* builds are compiled with -DUNICODE [as well as -D_UNICODE].
|
||||
*/
|
||||
#if defined(LP_SYS_WINCE) && !defined(FindFirstFile)
|
||||
# define FindFirstFile FindFirstFileW
|
||||
#endif
|
||||
#if defined(LP_SYS_WINCE) && !defined(FindNextFile)
|
||||
# define FindNextFile FindNextFileW
|
||||
#endif
|
||||
|
||||
#ifndef NAME_MAX
|
||||
# define NAME_MAX 255
|
||||
#endif
|
||||
|
||||
#ifdef CP_UTF8
|
||||
# define CP_DEFAULT CP_UTF8
|
||||
#else
|
||||
# define CP_DEFAULT CP_ACP
|
||||
#endif
|
||||
|
||||
struct LP_dir_context_st {
|
||||
WIN32_FIND_DATA ctx;
|
||||
HANDLE handle;
|
||||
char entry_name[NAME_MAX + 1];
|
||||
};
|
||||
|
||||
const char *LP_find_file(LP_DIR_CTX **ctx, const char *directory)
|
||||
{
|
||||
if (ctx == NULL || directory == NULL) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
if (*ctx == NULL) {
|
||||
size_t dirlen = strlen(directory);
|
||||
|
||||
if (dirlen == 0 || dirlen > INT_MAX - 3) {
|
||||
errno = ENOENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ctx = malloc(sizeof(**ctx));
|
||||
if (*ctx == NULL) {
|
||||
errno = ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
memset(*ctx, 0, sizeof(**ctx));
|
||||
|
||||
if (sizeof(TCHAR) != sizeof(char)) {
|
||||
TCHAR *wdir = NULL;
|
||||
/* len_0 denotes string length *with* trailing 0 */
|
||||
size_t index = 0, len_0 = dirlen + 1;
|
||||
#ifdef LP_MULTIBYTE_AVAILABLE
|
||||
int sz = 0;
|
||||
UINT cp;
|
||||
|
||||
do {
|
||||
# ifdef CP_UTF8
|
||||
if ((sz = MultiByteToWideChar((cp = CP_UTF8), 0,
|
||||
directory, len_0,
|
||||
NULL, 0)) > 0 ||
|
||||
GetLastError() != ERROR_NO_UNICODE_TRANSLATION)
|
||||
break;
|
||||
# endif
|
||||
sz = MultiByteToWideChar((cp = CP_ACP), 0,
|
||||
directory, len_0,
|
||||
NULL, 0);
|
||||
} while (0);
|
||||
|
||||
if (sz > 0) {
|
||||
/*
|
||||
* allocate two additional characters in case we need to
|
||||
* concatenate asterisk, |sz| covers trailing '\0'!
|
||||
*/
|
||||
wdir = _alloca((sz + 2) * sizeof(TCHAR));
|
||||
if (!MultiByteToWideChar(cp, 0, directory, len_0,
|
||||
(WCHAR *)wdir, sz)) {
|
||||
free(*ctx);
|
||||
*ctx = NULL;
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
sz = len_0;
|
||||
/*
|
||||
* allocate two additional characters in case we need to
|
||||
* concatenate asterisk, |sz| covers trailing '\0'!
|
||||
*/
|
||||
wdir = _alloca((sz + 2) * sizeof(TCHAR));
|
||||
for (index = 0; index < len_0; index++)
|
||||
wdir[index] = (TCHAR)directory[index];
|
||||
}
|
||||
|
||||
sz--; /* wdir[sz] is trailing '\0' now */
|
||||
if (wdir[sz - 1] != TEXT('*')) {
|
||||
if (wdir[sz - 1] != TEXT('/') && wdir[sz - 1] != TEXT('\\'))
|
||||
_tcscpy(wdir + sz, TEXT("/*"));
|
||||
else
|
||||
_tcscpy(wdir + sz, TEXT("*"));
|
||||
}
|
||||
|
||||
(*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx);
|
||||
} else {
|
||||
if (directory[dirlen - 1] != '*') {
|
||||
char *buf = _alloca(dirlen + 3);
|
||||
|
||||
strcpy(buf, directory);
|
||||
if (buf[dirlen - 1] != '/' && buf[dirlen - 1] != '\\')
|
||||
strcpy(buf + dirlen, "/*");
|
||||
else
|
||||
strcpy(buf + dirlen, "*");
|
||||
|
||||
directory = buf;
|
||||
}
|
||||
|
||||
(*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx);
|
||||
}
|
||||
|
||||
if ((*ctx)->handle == INVALID_HANDLE_VALUE) {
|
||||
free(*ctx);
|
||||
*ctx = NULL;
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (sizeof(TCHAR) != sizeof(char)) {
|
||||
TCHAR *wdir = (*ctx)->ctx.cFileName;
|
||||
size_t index, len_0 = 0;
|
||||
|
||||
while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1))
|
||||
len_0++;
|
||||
len_0++;
|
||||
|
||||
#ifdef LP_MULTIBYTE_AVAILABLE
|
||||
if (!WideCharToMultiByte(CP_DEFAULT, 0, (WCHAR *)wdir, len_0,
|
||||
(*ctx)->entry_name,
|
||||
sizeof((*ctx)->entry_name), NULL, 0))
|
||||
#endif
|
||||
for (index = 0; index < len_0; index++)
|
||||
(*ctx)->entry_name[index] = (char)wdir[index];
|
||||
} else
|
||||
strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName,
|
||||
sizeof((*ctx)->entry_name) - 1);
|
||||
|
||||
(*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0';
|
||||
|
||||
return (*ctx)->entry_name;
|
||||
}
|
||||
|
||||
int LP_find_file_end(LP_DIR_CTX **ctx)
|
||||
{
|
||||
if (ctx != NULL && *ctx != NULL) {
|
||||
FindClose((*ctx)->handle);
|
||||
free(*ctx);
|
||||
*ctx = NULL;
|
||||
return 1;
|
||||
}
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is dual-licensed and is also available under the following
|
||||
* terms:
|
||||
*
|
||||
* Copyright (c) 2004, Richard Levitte <richard@levitte.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define LP_SYS_WIN32
|
||||
#define LP_MULTIBYTE_AVAILABLE
|
||||
#include "LPdir_win.c"
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2004-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is dual-licensed and is also available under the following
|
||||
* terms:
|
||||
*
|
||||
* Copyright (c) 2004, Richard Levitte <richard@levitte.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define LP_SYS_WINCE
|
||||
/*
|
||||
* We might want to define LP_MULTIBYTE_AVAILABLE here. It's currently under
|
||||
* investigation what the exact conditions would be
|
||||
*/
|
||||
#include "LPdir_win.c"
|
||||
@@ -0,0 +1,156 @@
|
||||
Sparse Arrays
|
||||
=============
|
||||
|
||||
The `sparse_array.c` file contains an implementation of a sparse array that
|
||||
attempts to be both space and time efficient.
|
||||
|
||||
The sparse array is represented using a tree structure. Each node in the
|
||||
tree contains a block of pointers to either the user supplied leaf values or
|
||||
to another node.
|
||||
|
||||
There are a number of parameters used to define the block size:
|
||||
|
||||
OPENSSL_SA_BLOCK_BITS Specifies the number of bits covered by each block
|
||||
SA_BLOCK_MAX Specifies the number of pointers in each block
|
||||
SA_BLOCK_MASK Specifies a bit mask to perform modulo block size
|
||||
SA_BLOCK_MAX_LEVELS Indicates the maximum possible height of the tree
|
||||
|
||||
These constants are inter-related:
|
||||
|
||||
SA_BLOCK_MAX = 2 ^ OPENSSL_SA_BLOCK_BITS
|
||||
SA_BLOCK_MASK = SA_BLOCK_MAX - 1
|
||||
SA_BLOCK_MAX_LEVELS = number of bits in size_t divided by
|
||||
OPENSSL_SA_BLOCK_BITS rounded up to the next multiple
|
||||
of OPENSSL_SA_BLOCK_BITS
|
||||
|
||||
`OPENSSL_SA_BLOCK_BITS` can be defined at compile time and this overrides the
|
||||
built in setting.
|
||||
|
||||
As a space and performance optimisation, the height of the tree is usually
|
||||
less than the maximum possible height. Only sufficient height is allocated to
|
||||
accommodate the largest index added to the data structure.
|
||||
|
||||
The largest index used to add a value to the array determines the tree height:
|
||||
|
||||
+----------------------+---------------------+
|
||||
| Largest Added Index | Height of Tree |
|
||||
+----------------------+---------------------+
|
||||
| SA_BLOCK_MAX - 1 | 1 |
|
||||
| SA_BLOCK_MAX ^ 2 - 1 | 2 |
|
||||
| SA_BLOCK_MAX ^ 3 - 1 | 3 |
|
||||
| ... | ... |
|
||||
| size_t max | SA_BLOCK_MAX_LEVELS |
|
||||
+----------------------+---------------------+
|
||||
|
||||
The tree height is dynamically increased as needed based on additions.
|
||||
|
||||
An empty tree is represented by a NULL root pointer. Inserting a value at
|
||||
index 0 results in the allocation of a top level node full of null pointers
|
||||
except for the single pointer to the user's data (N = SA_BLOCK_MAX for
|
||||
brevity):
|
||||
|
||||
+----+
|
||||
|Root|
|
||||
|Node|
|
||||
+-+--+
|
||||
|
|
||||
|
|
||||
|
|
||||
v
|
||||
+-+-+---+---+---+---+
|
||||
| 0 | 1 | 2 |...|N-1|
|
||||
| |nil|nil|...|nil|
|
||||
+-+-+---+---+---+---+
|
||||
|
|
||||
|
|
||||
|
|
||||
v
|
||||
+-+--+
|
||||
|User|
|
||||
|Data|
|
||||
+----+
|
||||
Index 0
|
||||
|
||||
Inserting at element 2N+1 creates a new root node and pushes down the old root
|
||||
node. It then creates a second second level node to hold the pointer to the
|
||||
user's new data:
|
||||
|
||||
+----+
|
||||
|Root|
|
||||
|Node|
|
||||
+-+--+
|
||||
|
|
||||
|
|
||||
|
|
||||
v
|
||||
+-+-+---+---+---+---+
|
||||
| 0 | 1 | 2 |...|N-1|
|
||||
| |nil| |...|nil|
|
||||
+-+-+---+-+-+---+---+
|
||||
| |
|
||||
| +------------------+
|
||||
| |
|
||||
v v
|
||||
+-+-+---+---+---+---+ +-+-+---+---+---+---+
|
||||
| 0 | 1 | 2 |...|N-1| | 0 | 1 | 2 |...|N-1|
|
||||
|nil| |nil|...|nil| |nil| |nil|...|nil|
|
||||
+-+-+---+---+---+---+ +---+-+-+---+---+---+
|
||||
| |
|
||||
| |
|
||||
| |
|
||||
v v
|
||||
+-+--+ +-+--+
|
||||
|User| |User|
|
||||
|Data| |Data|
|
||||
+----+ +----+
|
||||
Index 0 Index 2N+1
|
||||
|
||||
The nodes themselves are allocated in a sparse manner. Only nodes which exist
|
||||
along a path from the root of the tree to an added leaf will be allocated.
|
||||
The complexity is hidden and nodes are allocated on an as needed basis.
|
||||
Because the data is expected to be sparse this doesn't result in a large waste
|
||||
of space.
|
||||
|
||||
Values can be removed from the sparse array by setting their index position to
|
||||
NULL. The data structure does not attempt to reclaim nodes or reduce the
|
||||
height of the tree on removal. For example, now setting index 0 to NULL would
|
||||
result in:
|
||||
|
||||
+----+
|
||||
|Root|
|
||||
|Node|
|
||||
+-+--+
|
||||
|
|
||||
|
|
||||
|
|
||||
v
|
||||
+-+-+---+---+---+---+
|
||||
| 0 | 1 | 2 |...|N-1|
|
||||
| |nil| |...|nil|
|
||||
+-+-+---+-+-+---+---+
|
||||
| |
|
||||
| +------------------+
|
||||
| |
|
||||
v v
|
||||
+-+-+---+---+---+---+ +-+-+---+---+---+---+
|
||||
| 0 | 1 | 2 |...|N-1| | 0 | 1 | 2 |...|N-1|
|
||||
|nil|nil|nil|...|nil| |nil| |nil|...|nil|
|
||||
+---+---+---+---+---+ +---+-+-+---+---+---+
|
||||
|
|
||||
|
|
||||
|
|
||||
v
|
||||
+-+--+
|
||||
|User|
|
||||
|Data|
|
||||
+----+
|
||||
Index 2N+1
|
||||
|
||||
Accesses to elements in the sparse array take O(log n) time where n is the
|
||||
largest element. The base of the logarithm is `SA_BLOCK_MAX`, so for moderately
|
||||
small indices (e.g. NIDs), single level (constant time) access is achievable.
|
||||
Space usage is O(minimum(m, n log(n)) where m is the number of elements in the
|
||||
array.
|
||||
|
||||
Note: sparse arrays only include pointers to types.
|
||||
Thus, `SPARSE_ARRAY_OF(char)` can be used to store a string.
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* AES low level APIs are deprecated for public use, but still ok for internal
|
||||
* use where we're using them to implement the higher level EVP interface, as is
|
||||
* the case here.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/modes.h>
|
||||
|
||||
void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t len, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc)
|
||||
{
|
||||
|
||||
if (enc)
|
||||
CRYPTO_cbc128_encrypt(in, out, len, key, ivec,
|
||||
(block128_f) AES_encrypt);
|
||||
else
|
||||
CRYPTO_cbc128_decrypt(in, out, len, key, ivec,
|
||||
(block128_f) AES_decrypt);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* AES_encrypt is deprecated - but we need to use it to implement these other
|
||||
* deprecated APIs.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/modes.h>
|
||||
|
||||
/*
|
||||
* The input and output encrypted as though 128bit cfb mode is being used.
|
||||
* The extra state information to record how much of the 128bit block we have
|
||||
* used is contained in *num;
|
||||
*/
|
||||
|
||||
void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc)
|
||||
{
|
||||
|
||||
CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc,
|
||||
(block128_f) AES_encrypt);
|
||||
}
|
||||
|
||||
/* N.B. This expects the input to be packed, MS bit first */
|
||||
void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc)
|
||||
{
|
||||
CRYPTO_cfb128_1_encrypt(in, out, length, key, ivec, num, enc,
|
||||
(block128_f) AES_encrypt);
|
||||
}
|
||||
|
||||
void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num, const int enc)
|
||||
{
|
||||
CRYPTO_cfb128_8_encrypt(in, out, length, key, ivec, num, enc,
|
||||
(block128_f) AES_encrypt);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
/*
|
||||
* AES_encrypt/AES_decrypt are deprecated - but we need to use them to implement
|
||||
* AES_ecb_encrypt
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include "aes_local.h"
|
||||
|
||||
void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
|
||||
const AES_KEY *key, const int enc)
|
||||
{
|
||||
|
||||
assert(in && out && key);
|
||||
assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
|
||||
|
||||
if (AES_ENCRYPT == enc)
|
||||
AES_encrypt(in, out, key);
|
||||
else
|
||||
AES_decrypt(in, out, key);
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Copyright 2006-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* AES_encrypt/AES_decrypt are deprecated - but we need to use them to implement
|
||||
* these functions
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include "aes_local.h"
|
||||
|
||||
/* XXX: probably some better way to do this */
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
# define UNALIGNED_MEMOPS_ARE_FAST 1
|
||||
#else
|
||||
# define UNALIGNED_MEMOPS_ARE_FAST 0
|
||||
#endif
|
||||
|
||||
#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long))
|
||||
typedef struct {
|
||||
unsigned long data[N_WORDS];
|
||||
#if defined(__GNUC__) && UNALIGNED_MEMOPS_ARE_FAST
|
||||
} aes_block_t __attribute((__aligned__(1)));
|
||||
#else
|
||||
} aes_block_t;
|
||||
#endif
|
||||
|
||||
#if UNALIGNED_MEMOPS_ARE_FAST
|
||||
# define load_block(d, s) (d) = *(const aes_block_t *)(s)
|
||||
# define store_block(d, s) *(aes_block_t *)(d) = (s)
|
||||
#else
|
||||
# define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE)
|
||||
# define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE)
|
||||
#endif
|
||||
|
||||
/* N.B. The IV for this mode is _twice_ the block size */
|
||||
|
||||
/* Use of this function is deprecated. */
|
||||
void AES_ige_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, const int enc)
|
||||
{
|
||||
size_t n;
|
||||
size_t len = length / AES_BLOCK_SIZE;
|
||||
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
OPENSSL_assert(in && out && key && ivec);
|
||||
OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
|
||||
OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
|
||||
|
||||
if (AES_ENCRYPT == enc) {
|
||||
if (in != out &&
|
||||
(UNALIGNED_MEMOPS_ARE_FAST
|
||||
|| ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
|
||||
0)) {
|
||||
aes_block_t *ivp = (aes_block_t *) ivec;
|
||||
aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
|
||||
|
||||
while (len) {
|
||||
aes_block_t *inp = (aes_block_t *) in;
|
||||
aes_block_t *outp = (aes_block_t *) out;
|
||||
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
outp->data[n] = inp->data[n] ^ ivp->data[n];
|
||||
AES_encrypt((unsigned char *)outp->data,
|
||||
(unsigned char *)outp->data, key);
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
outp->data[n] ^= iv2p->data[n];
|
||||
ivp = outp;
|
||||
iv2p = inp;
|
||||
--len;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
|
||||
memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
|
||||
} else {
|
||||
aes_block_t tmp, tmp2;
|
||||
aes_block_t iv;
|
||||
aes_block_t iv2;
|
||||
|
||||
load_block(iv, ivec);
|
||||
load_block(iv2, ivec + AES_BLOCK_SIZE);
|
||||
|
||||
while (len) {
|
||||
load_block(tmp, in);
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
tmp2.data[n] = tmp.data[n] ^ iv.data[n];
|
||||
AES_encrypt((unsigned char *)tmp2.data,
|
||||
(unsigned char *)tmp2.data, key);
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
tmp2.data[n] ^= iv2.data[n];
|
||||
store_block(out, tmp2);
|
||||
iv = tmp2;
|
||||
iv2 = tmp;
|
||||
--len;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(ivec, iv.data, AES_BLOCK_SIZE);
|
||||
memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
|
||||
}
|
||||
} else {
|
||||
if (in != out &&
|
||||
(UNALIGNED_MEMOPS_ARE_FAST
|
||||
|| ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(long) ==
|
||||
0)) {
|
||||
aes_block_t *ivp = (aes_block_t *) ivec;
|
||||
aes_block_t *iv2p = (aes_block_t *) (ivec + AES_BLOCK_SIZE);
|
||||
|
||||
while (len) {
|
||||
aes_block_t tmp;
|
||||
aes_block_t *inp = (aes_block_t *) in;
|
||||
aes_block_t *outp = (aes_block_t *) out;
|
||||
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
tmp.data[n] = inp->data[n] ^ iv2p->data[n];
|
||||
AES_decrypt((unsigned char *)tmp.data,
|
||||
(unsigned char *)outp->data, key);
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
outp->data[n] ^= ivp->data[n];
|
||||
ivp = inp;
|
||||
iv2p = outp;
|
||||
--len;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(ivec, ivp->data, AES_BLOCK_SIZE);
|
||||
memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE);
|
||||
} else {
|
||||
aes_block_t tmp, tmp2;
|
||||
aes_block_t iv;
|
||||
aes_block_t iv2;
|
||||
|
||||
load_block(iv, ivec);
|
||||
load_block(iv2, ivec + AES_BLOCK_SIZE);
|
||||
|
||||
while (len) {
|
||||
load_block(tmp, in);
|
||||
tmp2 = tmp;
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
tmp.data[n] ^= iv2.data[n];
|
||||
AES_decrypt((unsigned char *)tmp.data,
|
||||
(unsigned char *)tmp.data, key);
|
||||
for (n = 0; n < N_WORDS; ++n)
|
||||
tmp.data[n] ^= iv.data[n];
|
||||
store_block(out, tmp);
|
||||
iv = tmp2;
|
||||
iv2 = tmp;
|
||||
--len;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
memcpy(ivec, iv.data, AES_BLOCK_SIZE);
|
||||
memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that its effectively impossible to do biIGE in anything other
|
||||
* than a single pass, so no provision is made for chaining.
|
||||
*
|
||||
* NB: The implementation of AES_bi_ige_encrypt has a bug. It is supposed to use
|
||||
* 2 AES keys, but in fact only one is ever used. This bug has been present
|
||||
* since this code was first implemented. It is believed to have minimal
|
||||
* security impact in practice and has therefore not been fixed for backwards
|
||||
* compatibility reasons.
|
||||
*
|
||||
* Use of this function is deprecated.
|
||||
*/
|
||||
|
||||
/* N.B. The IV for this mode is _four times_ the block size */
|
||||
|
||||
void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
const AES_KEY *key2, const unsigned char *ivec,
|
||||
const int enc)
|
||||
{
|
||||
size_t n;
|
||||
size_t len = length;
|
||||
unsigned char tmp[AES_BLOCK_SIZE];
|
||||
unsigned char tmp2[AES_BLOCK_SIZE];
|
||||
unsigned char tmp3[AES_BLOCK_SIZE];
|
||||
unsigned char prev[AES_BLOCK_SIZE];
|
||||
const unsigned char *iv;
|
||||
const unsigned char *iv2;
|
||||
|
||||
OPENSSL_assert(in && out && key && ivec);
|
||||
OPENSSL_assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc));
|
||||
OPENSSL_assert((length % AES_BLOCK_SIZE) == 0);
|
||||
|
||||
if (AES_ENCRYPT == enc) {
|
||||
/*
|
||||
* XXX: Do a separate case for when in != out (strictly should check
|
||||
* for overlap, too)
|
||||
*/
|
||||
|
||||
/* First the forward pass */
|
||||
iv = ivec;
|
||||
iv2 = ivec + AES_BLOCK_SIZE;
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] = in[n] ^ iv[n];
|
||||
AES_encrypt(out, out, key);
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] ^= iv2[n];
|
||||
iv = out;
|
||||
memcpy(prev, in, AES_BLOCK_SIZE);
|
||||
iv2 = prev;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* And now backwards */
|
||||
iv = ivec + AES_BLOCK_SIZE * 2;
|
||||
iv2 = ivec + AES_BLOCK_SIZE * 3;
|
||||
len = length;
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
out -= AES_BLOCK_SIZE;
|
||||
/*
|
||||
* XXX: reduce copies by alternating between buffers
|
||||
*/
|
||||
memcpy(tmp, out, AES_BLOCK_SIZE);
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] ^= iv[n];
|
||||
/*
|
||||
* hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE);
|
||||
*/
|
||||
AES_encrypt(out, out, key);
|
||||
/*
|
||||
* hexdump(stdout,"enc", out, AES_BLOCK_SIZE);
|
||||
*/
|
||||
/*
|
||||
* hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE);
|
||||
*/
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] ^= iv2[n];
|
||||
/*
|
||||
* hexdump(stdout,"out", out, AES_BLOCK_SIZE);
|
||||
*/
|
||||
iv = out;
|
||||
memcpy(prev, tmp, AES_BLOCK_SIZE);
|
||||
iv2 = prev;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
} else {
|
||||
/* First backwards */
|
||||
iv = ivec + AES_BLOCK_SIZE * 2;
|
||||
iv2 = ivec + AES_BLOCK_SIZE * 3;
|
||||
in += length;
|
||||
out += length;
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
in -= AES_BLOCK_SIZE;
|
||||
out -= AES_BLOCK_SIZE;
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
memcpy(tmp2, in, AES_BLOCK_SIZE);
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n)
|
||||
tmp[n] ^= iv2[n];
|
||||
AES_decrypt(tmp, out, key);
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] ^= iv[n];
|
||||
memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
|
||||
iv = tmp3;
|
||||
iv2 = out;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
/* And now forwards */
|
||||
iv = ivec;
|
||||
iv2 = ivec + AES_BLOCK_SIZE;
|
||||
len = length;
|
||||
while (len >= AES_BLOCK_SIZE) {
|
||||
memcpy(tmp, out, AES_BLOCK_SIZE);
|
||||
memcpy(tmp2, out, AES_BLOCK_SIZE);
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n)
|
||||
tmp[n] ^= iv2[n];
|
||||
AES_decrypt(tmp, out, key);
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n)
|
||||
out[n] ^= iv[n];
|
||||
memcpy(tmp3, tmp2, AES_BLOCK_SIZE);
|
||||
iv = tmp3;
|
||||
iv2 = out;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2002-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef OSSL_CRYPTO_AES_LOCAL_H
|
||||
# define OSSL_CRYPTO_AES_LOCAL_H
|
||||
|
||||
# include <openssl/e_os2.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
# include <string.h>
|
||||
|
||||
# if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
|
||||
# define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
|
||||
# define GETU32(p) SWAP(*((u32 *)(p)))
|
||||
# define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
|
||||
# else
|
||||
# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
|
||||
# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
|
||||
# endif
|
||||
|
||||
typedef uint64_t u64;
|
||||
# ifdef AES_LONG
|
||||
typedef unsigned long u32;
|
||||
# else
|
||||
typedef unsigned int u32;
|
||||
# endif
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned char u8;
|
||||
|
||||
# define MAXKC (256/32)
|
||||
# define MAXKB (256/8)
|
||||
# define MAXNR 14
|
||||
|
||||
/* This controls loop-unrolling in aes_core.c */
|
||||
# undef FULL_UNROLL
|
||||
|
||||
#endif /* !OSSL_CRYPTO_AES_LOCAL_H */
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/aes.h>
|
||||
#include "aes_local.h"
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
const char *AES_options(void)
|
||||
{
|
||||
# ifdef FULL_UNROLL
|
||||
return "aes(full)";
|
||||
# else
|
||||
return "aes(partial)";
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* AES_encrypt is deprecated - but we need to use it to implement
|
||||
* AES_ofb128_encrypt
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/modes.h>
|
||||
|
||||
void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
|
||||
size_t length, const AES_KEY *key,
|
||||
unsigned char *ivec, int *num)
|
||||
{
|
||||
CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num,
|
||||
(block128_f) AES_encrypt);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2008-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* AES_encrypt/AES_decrypt are deprecated - but we need to use them to implement
|
||||
* these functions
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/modes.h>
|
||||
|
||||
int AES_wrap_key(AES_KEY *key, const unsigned char *iv,
|
||||
unsigned char *out,
|
||||
const unsigned char *in, unsigned int inlen)
|
||||
{
|
||||
return CRYPTO_128_wrap(key, iv, out, in, inlen, (block128_f) AES_encrypt);
|
||||
}
|
||||
|
||||
int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,
|
||||
unsigned char *out,
|
||||
const unsigned char *in, unsigned int inlen)
|
||||
{
|
||||
return CRYPTO_128_unwrap(key, iv, out, in, inlen,
|
||||
(block128_f) AES_decrypt);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1089
File diff suppressed because it is too large
Load Diff
+594
@@ -0,0 +1,594 @@
|
||||
#! /usr/bin/env perl
|
||||
# This file is dual-licensed, meaning that you can use it under your
|
||||
# choice of either of the following two licenses:
|
||||
#
|
||||
# Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You can obtain
|
||||
# a copy in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
#
|
||||
# or
|
||||
#
|
||||
# Copyright (c) 2022, Hongren (Zenithal) Zheng <i@zenithal.me>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib "$Bin";
|
||||
use lib "$Bin/../../perlasm";
|
||||
use riscv;
|
||||
|
||||
# $output is the last argument if it looks like a file (it has an extension)
|
||||
# $flavour is the first argument if it doesn't look like a file
|
||||
my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
|
||||
my $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
|
||||
|
||||
$output and open STDOUT,">$output";
|
||||
|
||||
################################################################################
|
||||
# Utility functions to help with keeping track of which registers to stack/
|
||||
# unstack when entering / exiting routines.
|
||||
################################################################################
|
||||
{
|
||||
# Callee-saved registers
|
||||
my @callee_saved = map("x$_",(2,8,9,18..27));
|
||||
# Caller-saved registers
|
||||
my @caller_saved = map("x$_",(1,5..7,10..17,28..31));
|
||||
my @must_save;
|
||||
sub use_reg {
|
||||
my $reg = shift;
|
||||
if (grep(/^$reg$/, @callee_saved)) {
|
||||
push(@must_save, $reg);
|
||||
} elsif (!grep(/^$reg$/, @caller_saved)) {
|
||||
# Register is not usable!
|
||||
die("Unusable register ".$reg);
|
||||
}
|
||||
return $reg;
|
||||
}
|
||||
sub use_regs {
|
||||
return map(use_reg("x$_"), @_);
|
||||
}
|
||||
sub save_regs {
|
||||
my $ret = '';
|
||||
my $stack_reservation = ($#must_save + 1) * 8;
|
||||
my $stack_offset = $stack_reservation;
|
||||
if ($stack_reservation % 16) {
|
||||
$stack_reservation += 8;
|
||||
}
|
||||
$ret.=" addi sp,sp,-$stack_reservation\n";
|
||||
foreach (@must_save) {
|
||||
$stack_offset -= 8;
|
||||
$ret.=" sd $_,$stack_offset(sp)\n";
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
sub load_regs {
|
||||
my $ret = '';
|
||||
my $stack_reservation = ($#must_save + 1) * 8;
|
||||
my $stack_offset = $stack_reservation;
|
||||
if ($stack_reservation % 16) {
|
||||
$stack_reservation += 8;
|
||||
}
|
||||
foreach (@must_save) {
|
||||
$stack_offset -= 8;
|
||||
$ret.=" ld $_,$stack_offset(sp)\n";
|
||||
}
|
||||
$ret.=" addi sp,sp,$stack_reservation\n";
|
||||
return $ret;
|
||||
}
|
||||
sub clear_regs {
|
||||
@must_save = ();
|
||||
}
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# Register assignment for rv64i_zkne_encrypt and rv64i_zknd_decrypt
|
||||
################################################################################
|
||||
|
||||
# Registers to hold AES state (called s0-s3 or y0-y3 elsewhere)
|
||||
my ($Q0,$Q1,$Q2,$Q3) = use_regs(6..9);
|
||||
|
||||
# Function arguments (x10-x12 are a0-a2 in the ABI)
|
||||
# Input block pointer, output block pointer, key pointer
|
||||
my ($INP,$OUTP,$KEYP) = use_regs(10..12);
|
||||
|
||||
# Temporaries
|
||||
my ($T0,$T1) = use_regs(13..14);
|
||||
|
||||
# Loop counter
|
||||
my ($loopcntr) = use_regs(30);
|
||||
|
||||
################################################################################
|
||||
# void rv64i_zkne_encrypt(const unsigned char *in, unsigned char *out,
|
||||
# const AES_KEY *key);
|
||||
################################################################################
|
||||
my $code .= <<___;
|
||||
.text
|
||||
.balign 16
|
||||
.globl rv64i_zkne_encrypt
|
||||
.type rv64i_zkne_encrypt,\@function
|
||||
rv64i_zkne_encrypt:
|
||||
___
|
||||
|
||||
$code .= save_regs();
|
||||
|
||||
$code .= <<___;
|
||||
|
||||
# Load input to block cipher
|
||||
ld $Q0,0($INP)
|
||||
ld $Q1,8($INP)
|
||||
|
||||
# Load key
|
||||
ld $T0,0($KEYP)
|
||||
ld $T1,8($KEYP)
|
||||
|
||||
# Load number of rounds
|
||||
lwu $loopcntr,240($KEYP)
|
||||
|
||||
# initial transformation
|
||||
xor $Q0,$Q0,$T0
|
||||
xor $Q1,$Q1,$T1
|
||||
|
||||
# The main loop only executes the first N-1 rounds.
|
||||
add $loopcntr,$loopcntr,-1
|
||||
|
||||
# Do Nr - 1 rounds (final round is special)
|
||||
1:
|
||||
@{[aes64esm $Q2,$Q0,$Q1]}
|
||||
@{[aes64esm $Q3,$Q1,$Q0]}
|
||||
|
||||
# Update key ptr to point to next key in schedule
|
||||
add $KEYP,$KEYP,16
|
||||
|
||||
# Grab next key in schedule
|
||||
ld $T0,0($KEYP)
|
||||
ld $T1,8($KEYP)
|
||||
xor $Q0,$Q2,$T0
|
||||
xor $Q1,$Q3,$T1
|
||||
|
||||
add $loopcntr,$loopcntr,-1
|
||||
bgtz $loopcntr,1b
|
||||
|
||||
# final round
|
||||
@{[aes64es $Q2,$Q0,$Q1]}
|
||||
@{[aes64es $Q3,$Q1,$Q0]}
|
||||
|
||||
# since not added 16 before
|
||||
ld $T0,16($KEYP)
|
||||
ld $T1,24($KEYP)
|
||||
xor $Q0,$Q2,$T0
|
||||
xor $Q1,$Q3,$T1
|
||||
|
||||
sd $Q0,0($OUTP)
|
||||
sd $Q1,8($OUTP)
|
||||
|
||||
# Pop registers and return
|
||||
___
|
||||
|
||||
$code .= load_regs();
|
||||
|
||||
$code .= <<___;
|
||||
ret
|
||||
___
|
||||
|
||||
################################################################################
|
||||
# void rv64i_zknd_decrypt(const unsigned char *in, unsigned char *out,
|
||||
# const AES_KEY *key);
|
||||
################################################################################
|
||||
$code .= <<___;
|
||||
.text
|
||||
.balign 16
|
||||
.globl rv64i_zknd_decrypt
|
||||
.type rv64i_zknd_decrypt,\@function
|
||||
rv64i_zknd_decrypt:
|
||||
___
|
||||
|
||||
$code .= save_regs();
|
||||
|
||||
$code .= <<___;
|
||||
|
||||
# Load input to block cipher
|
||||
ld $Q0,0($INP)
|
||||
ld $Q1,8($INP)
|
||||
|
||||
# Load number of rounds
|
||||
lwu $loopcntr,240($KEYP)
|
||||
|
||||
# Load the last key
|
||||
slli $T0,$loopcntr,4
|
||||
add $KEYP,$KEYP,$T0
|
||||
ld $T0,0($KEYP)
|
||||
ld $T1,8($KEYP)
|
||||
|
||||
xor $Q0,$Q0,$T0
|
||||
xor $Q1,$Q1,$T1
|
||||
|
||||
# The main loop only executes the first N-1 rounds.
|
||||
add $loopcntr,$loopcntr,-1
|
||||
|
||||
# Do Nr - 1 rounds (final round is special)
|
||||
1:
|
||||
@{[aes64dsm $Q2,$Q0,$Q1]}
|
||||
@{[aes64dsm $Q3,$Q1,$Q0]}
|
||||
|
||||
# Update key ptr to point to next key in schedule
|
||||
add $KEYP,$KEYP,-16
|
||||
|
||||
# Grab next key in schedule
|
||||
ld $T0,0($KEYP)
|
||||
ld $T1,8($KEYP)
|
||||
xor $Q0,$Q2,$T0
|
||||
xor $Q1,$Q3,$T1
|
||||
|
||||
add $loopcntr,$loopcntr,-1
|
||||
bgtz $loopcntr,1b
|
||||
|
||||
# final round
|
||||
@{[aes64ds $Q2,$Q0,$Q1]}
|
||||
@{[aes64ds $Q3,$Q1,$Q0]}
|
||||
|
||||
add $KEYP,$KEYP,-16
|
||||
ld $T0,0($KEYP)
|
||||
ld $T1,8($KEYP)
|
||||
xor $Q0,$Q2,$T0
|
||||
xor $Q1,$Q3,$T1
|
||||
|
||||
sd $Q0,0($OUTP)
|
||||
sd $Q1,8($OUTP)
|
||||
# Pop registers and return
|
||||
___
|
||||
|
||||
$code .= load_regs();
|
||||
|
||||
$code .= <<___;
|
||||
ret
|
||||
___
|
||||
|
||||
clear_regs();
|
||||
|
||||
################################################################################
|
||||
# Register assignment for rv64i_zkn[e/d]_set_[en/de]crypt_key
|
||||
################################################################################
|
||||
|
||||
# Function arguments (x10-x12 are a0-a2 in the ABI)
|
||||
# Pointer to user key, number of bits in key, key pointer
|
||||
my ($UKEY,$BITS,$KEYP) = use_regs(10..12);
|
||||
|
||||
# Temporaries
|
||||
my ($T0,$T1,$T2,$T3,$T4) = use_regs(6..8,13..14);
|
||||
|
||||
################################################################################
|
||||
# utility functions for rv64i_zkne_set_encrypt_key
|
||||
################################################################################
|
||||
sub ke128enc {
|
||||
my $rnum = 0;
|
||||
my $ret = '';
|
||||
$ret .= <<___;
|
||||
ld $T0,0($UKEY)
|
||||
ld $T1,8($UKEY)
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
___
|
||||
while($rnum < 10) {
|
||||
$ret .= <<___;
|
||||
@{[aes64ks1i $T2,$T1,$rnum]}
|
||||
@{[aes64ks2 $T0,$T2,$T0]}
|
||||
@{[aes64ks2 $T1,$T0,$T1]}
|
||||
add $KEYP,$KEYP,16
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
___
|
||||
$rnum++;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub ke192enc {
|
||||
my $rnum = 0;
|
||||
my $ret = '';
|
||||
$ret .= <<___;
|
||||
ld $T0,0($UKEY)
|
||||
ld $T1,8($UKEY)
|
||||
ld $T2,16($UKEY)
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
sd $T2,16($KEYP)
|
||||
___
|
||||
while($rnum < 8) {
|
||||
$ret .= <<___;
|
||||
@{[aes64ks1i $T3,$T2,$rnum]}
|
||||
@{[aes64ks2 $T0,$T3,$T0]}
|
||||
@{[aes64ks2 $T1,$T0,$T1]}
|
||||
___
|
||||
if ($rnum != 7) {
|
||||
# note that (8+1)*24 = 216, (12+1)*16 = 208
|
||||
# thus the last 8 bytes can be dropped
|
||||
$ret .= <<___;
|
||||
@{[aes64ks2 $T2,$T1,$T2]}
|
||||
___
|
||||
}
|
||||
$ret .= <<___;
|
||||
add $KEYP,$KEYP,24
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
___
|
||||
if ($rnum != 7) {
|
||||
$ret .= <<___;
|
||||
sd $T2,16($KEYP)
|
||||
___
|
||||
}
|
||||
$rnum++;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub ke256enc {
|
||||
my $rnum = 0;
|
||||
my $ret = '';
|
||||
$ret .= <<___;
|
||||
ld $T0,0($UKEY)
|
||||
ld $T1,8($UKEY)
|
||||
ld $T2,16($UKEY)
|
||||
ld $T3,24($UKEY)
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
sd $T2,16($KEYP)
|
||||
sd $T3,24($KEYP)
|
||||
___
|
||||
while($rnum < 7) {
|
||||
$ret .= <<___;
|
||||
@{[aes64ks1i $T4,$T3,$rnum]}
|
||||
@{[aes64ks2 $T0,$T4,$T0]}
|
||||
@{[aes64ks2 $T1,$T0,$T1]}
|
||||
add $KEYP,$KEYP,32
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
___
|
||||
if ($rnum != 6) {
|
||||
# note that (7+1)*32 = 256, (14+1)*16 = 240
|
||||
# thus the last 16 bytes can be dropped
|
||||
$ret .= <<___;
|
||||
@{[aes64ks1i $T4,$T1,0xA]}
|
||||
@{[aes64ks2 $T2,$T4,$T2]}
|
||||
@{[aes64ks2 $T3,$T2,$T3]}
|
||||
sd $T2,16($KEYP)
|
||||
sd $T3,24($KEYP)
|
||||
___
|
||||
}
|
||||
$rnum++;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# void rv64i_zkne_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||
# AES_KEY *key)
|
||||
################################################################################
|
||||
sub AES_set_common {
|
||||
my ($ke128, $ke192, $ke256) = @_;
|
||||
my $ret = '';
|
||||
$ret .= <<___;
|
||||
bnez $UKEY,1f # if (!userKey || !key) return -1;
|
||||
bnez $KEYP,1f
|
||||
li a0,-1
|
||||
ret
|
||||
1:
|
||||
# Determine number of rounds from key size in bits
|
||||
li $T0,128
|
||||
bne $BITS,$T0,1f
|
||||
li $T1,10 # key->rounds = 10 if bits == 128
|
||||
sw $T1,240($KEYP) # store key->rounds
|
||||
$ke128
|
||||
j 4f
|
||||
1:
|
||||
li $T0,192
|
||||
bne $BITS,$T0,2f
|
||||
li $T1,12 # key->rounds = 12 if bits == 192
|
||||
sw $T1,240($KEYP) # store key->rounds
|
||||
$ke192
|
||||
j 4f
|
||||
2:
|
||||
li $T1,14 # key->rounds = 14 if bits == 256
|
||||
li $T0,256
|
||||
beq $BITS,$T0,3f
|
||||
li a0,-2 # If bits != 128, 192, or 256, return -2
|
||||
j 5f
|
||||
3:
|
||||
sw $T1,240($KEYP) # store key->rounds
|
||||
$ke256
|
||||
4: # return 0
|
||||
li a0,0
|
||||
5: # return a0
|
||||
___
|
||||
return $ret;
|
||||
}
|
||||
$code .= <<___;
|
||||
.text
|
||||
.balign 16
|
||||
.globl rv64i_zkne_set_encrypt_key
|
||||
.type rv64i_zkne_set_encrypt_key,\@function
|
||||
rv64i_zkne_set_encrypt_key:
|
||||
___
|
||||
$code .= save_regs();
|
||||
$code .= AES_set_common(ke128enc(), ke192enc(),ke256enc());
|
||||
$code .= load_regs();
|
||||
$code .= <<___;
|
||||
ret
|
||||
___
|
||||
|
||||
################################################################################
|
||||
# utility functions for rv64i_zknd_set_decrypt_key
|
||||
################################################################################
|
||||
sub ke128dec {
|
||||
my $rnum = 0;
|
||||
my $ret = '';
|
||||
$ret .= <<___;
|
||||
ld $T0,0($UKEY)
|
||||
ld $T1,8($UKEY)
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
___
|
||||
while($rnum < 10) {
|
||||
$ret .= <<___;
|
||||
@{[aes64ks1i $T2,$T1,$rnum]}
|
||||
@{[aes64ks2 $T0,$T2,$T0]}
|
||||
@{[aes64ks2 $T1,$T0,$T1]}
|
||||
add $KEYP,$KEYP,16
|
||||
___
|
||||
# need to aes64im for [1:N-1] round keys
|
||||
# this is from the fact that aes64dsm subwords first then mix column
|
||||
# intuitively decryption needs to first mix column then subwords
|
||||
# however, for merging datapaths (encryption first subwords then mix column)
|
||||
# aes64dsm chooses to inverse the order of them, thus
|
||||
# transform should then be done on the round key
|
||||
if ($rnum < 9) {
|
||||
$ret .= <<___;
|
||||
@{[aes64im $T2,$T0]}
|
||||
sd $T2,0($KEYP)
|
||||
@{[aes64im $T2,$T1]}
|
||||
sd $T2,8($KEYP)
|
||||
___
|
||||
} else {
|
||||
$ret .= <<___;
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
___
|
||||
}
|
||||
$rnum++;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub ke192dec {
|
||||
my $rnum = 0;
|
||||
my $ret = '';
|
||||
$ret .= <<___;
|
||||
ld $T0,0($UKEY)
|
||||
ld $T1,8($UKEY)
|
||||
ld $T2,16($UKEY)
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
@{[aes64im $T3,$T2]}
|
||||
sd $T3,16($KEYP)
|
||||
___
|
||||
while($rnum < 8) {
|
||||
$ret .= <<___;
|
||||
@{[aes64ks1i $T3,$T2,$rnum]}
|
||||
@{[aes64ks2 $T0,$T3,$T0]}
|
||||
@{[aes64ks2 $T1,$T0,$T1]}
|
||||
add $KEYP,$KEYP,24
|
||||
___
|
||||
if ($rnum < 7) {
|
||||
$ret .= <<___;
|
||||
@{[aes64im $T3,$T0]}
|
||||
sd $T3,0($KEYP)
|
||||
@{[aes64im $T3,$T1]}
|
||||
sd $T3,8($KEYP)
|
||||
# the reason is in ke192enc
|
||||
@{[aes64ks2 $T2,$T1,$T2]}
|
||||
@{[aes64im $T3,$T2]}
|
||||
sd $T3,16($KEYP)
|
||||
___
|
||||
} else { # rnum == 7
|
||||
$ret .= <<___;
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
___
|
||||
}
|
||||
$rnum++;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub ke256dec {
|
||||
my $rnum = 0;
|
||||
my $ret = '';
|
||||
$ret .= <<___;
|
||||
ld $T0,0($UKEY)
|
||||
ld $T1,8($UKEY)
|
||||
ld $T2,16($UKEY)
|
||||
ld $T3,24($UKEY)
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
@{[aes64im $T4,$T2]}
|
||||
sd $T4,16($KEYP)
|
||||
@{[aes64im $T4,$T3]}
|
||||
sd $T4,24($KEYP)
|
||||
___
|
||||
while($rnum < 7) {
|
||||
$ret .= <<___;
|
||||
@{[aes64ks1i $T4,$T3,$rnum]}
|
||||
@{[aes64ks2 $T0,$T4,$T0]}
|
||||
@{[aes64ks2 $T1,$T0,$T1]}
|
||||
add $KEYP,$KEYP,32
|
||||
___
|
||||
if ($rnum < 6) {
|
||||
$ret .= <<___;
|
||||
@{[aes64ks1i $T4,$T1,0xA]}
|
||||
@{[aes64ks2 $T2,$T4,$T2]}
|
||||
@{[aes64ks2 $T3,$T2,$T3]}
|
||||
@{[aes64im $T4,$T0]}
|
||||
sd $T4,0($KEYP)
|
||||
@{[aes64im $T4,$T1]}
|
||||
sd $T4,8($KEYP)
|
||||
@{[aes64im $T4,$T2]}
|
||||
sd $T4,16($KEYP)
|
||||
@{[aes64im $T4,$T3]}
|
||||
sd $T4,24($KEYP)
|
||||
___
|
||||
} else {
|
||||
$ret .= <<___;
|
||||
sd $T0,0($KEYP)
|
||||
sd $T1,8($KEYP)
|
||||
# last two one dropped
|
||||
___
|
||||
}
|
||||
$rnum++;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
################################################################################
|
||||
# void rv64i_zknd_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||
# AES_KEY *key)
|
||||
################################################################################
|
||||
$code .= <<___;
|
||||
.text
|
||||
.balign 16
|
||||
.globl rv64i_zknd_set_decrypt_key
|
||||
.type rv64i_zknd_set_decrypt_key,\@function
|
||||
rv64i_zknd_set_decrypt_key:
|
||||
___
|
||||
$code .= save_regs();
|
||||
$code .= AES_set_common(ke128dec(), ke192dec(),ke256dec());
|
||||
$code .= load_regs();
|
||||
$code .= <<___;
|
||||
ret
|
||||
___
|
||||
|
||||
print $code;
|
||||
close STDOUT or die "error closing STDOUT: $!";
|
||||
+710
@@ -0,0 +1,710 @@
|
||||
#! /usr/bin/env perl
|
||||
# This file is dual-licensed, meaning that you can use it under your
|
||||
# choice of either of the following two licenses:
|
||||
#
|
||||
# Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You can obtain
|
||||
# a copy in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
#
|
||||
# or
|
||||
#
|
||||
# Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# - RV64I
|
||||
# - RISC-V Vector ('V') with VLEN >= 128
|
||||
# - RISC-V Vector Bit-manipulation extension ('Zvbb')
|
||||
# - RISC-V Vector GCM/GMAC extension ('Zvkg')
|
||||
# - RISC-V Vector AES block cipher extension ('Zvkned')
|
||||
# - RISC-V Zicclsm(Main memory supports misaligned loads/stores)
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib "$Bin";
|
||||
use lib "$Bin/../../perlasm";
|
||||
use riscv;
|
||||
|
||||
# $output is the last argument if it looks like a file (it has an extension)
|
||||
# $flavour is the first argument if it doesn't look like a file
|
||||
my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
|
||||
my $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
|
||||
|
||||
$output and open STDOUT,">$output";
|
||||
|
||||
my $code=<<___;
|
||||
.text
|
||||
___
|
||||
|
||||
{
|
||||
################################################################################
|
||||
# void rv64i_zvbb_zvkg_zvkned_aes_xts_encrypt(const unsigned char *in,
|
||||
# unsigned char *out, size_t length,
|
||||
# const AES_KEY *key1,
|
||||
# const AES_KEY *key2,
|
||||
# const unsigned char iv[16])
|
||||
my ($INPUT, $OUTPUT, $LENGTH, $KEY1, $KEY2, $IV) = ("a0", "a1", "a2", "a3", "a4", "a5");
|
||||
my ($TAIL_LENGTH) = ("a6");
|
||||
my ($VL) = ("a7");
|
||||
my ($T0, $T1, $T2) = ("t0", "t1", "t2");
|
||||
my ($STORE_LEN32) = ("t3");
|
||||
my ($LEN32) = ("t4");
|
||||
my ($V0, $V1, $V2, $V3, $V4, $V5, $V6, $V7,
|
||||
$V8, $V9, $V10, $V11, $V12, $V13, $V14, $V15,
|
||||
$V16, $V17, $V18, $V19, $V20, $V21, $V22, $V23,
|
||||
$V24, $V25, $V26, $V27, $V28, $V29, $V30, $V31,
|
||||
) = map("v$_",(0..31));
|
||||
|
||||
sub compute_xts_iv0 {
|
||||
my $code=<<___;
|
||||
# Load number of rounds
|
||||
lwu $T0, 240($KEY2)
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vle32_v $V28, $IV]}
|
||||
@{[vle32_v $V29, $KEY2]}
|
||||
@{[vaesz_vs $V28, $V29]}
|
||||
addi $T0, $T0, -1
|
||||
addi $KEY2, $KEY2, 16
|
||||
1:
|
||||
@{[vle32_v $V29, $KEY2]}
|
||||
@{[vaesem_vs $V28, $V29]}
|
||||
addi $T0, $T0, -1
|
||||
addi $KEY2, $KEY2, 16
|
||||
bnez $T0, 1b
|
||||
@{[vle32_v $V29, $KEY2]}
|
||||
@{[vaesef_vs $V28, $V29]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# prepare input data(v24), iv(v28), bit-reversed-iv(v16), bit-reversed-iv-multiplier(v20)
|
||||
sub init_first_round {
|
||||
my $code=<<___;
|
||||
# load input
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
@{[vle32_v $V24, $INPUT]}
|
||||
|
||||
li $T0, 5
|
||||
# We could simplify the initialization steps if we have `block<=1`.
|
||||
blt $LEN32, $T0, 1f
|
||||
|
||||
# Note: We use `vgmul` for GF(2^128) multiplication. The `vgmul` uses
|
||||
# different order of coefficients. We should use`vbrev8` to reverse the
|
||||
# data when we use `vgmul`.
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vbrev8_v $V0, $V28]}
|
||||
@{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
@{[vmv_v_i $V16, 0]}
|
||||
# v16: [r-IV0, r-IV0, ...]
|
||||
@{[vaesz_vs $V16, $V0]}
|
||||
|
||||
# Prepare GF(2^128) multiplier [1, x, x^2, x^3, ...] in v8.
|
||||
slli $T0, $LEN32, 2
|
||||
@{[vsetvli "zero", $T0, "e32", "m1", "ta", "ma"]}
|
||||
# v2: [`1`, `1`, `1`, `1`, ...]
|
||||
@{[vmv_v_i $V2, 1]}
|
||||
# v3: [`0`, `1`, `2`, `3`, ...]
|
||||
@{[vid_v $V3]}
|
||||
@{[vsetvli "zero", $T0, "e64", "m2", "ta", "ma"]}
|
||||
# v4: [`1`, 0, `1`, 0, `1`, 0, `1`, 0, ...]
|
||||
@{[vzext_vf2 $V4, $V2]}
|
||||
# v6: [`0`, 0, `1`, 0, `2`, 0, `3`, 0, ...]
|
||||
@{[vzext_vf2 $V6, $V3]}
|
||||
slli $T0, $LEN32, 1
|
||||
@{[vsetvli "zero", $T0, "e32", "m2", "ta", "ma"]}
|
||||
# v8: [1<<0=1, 0, 0, 0, 1<<1=x, 0, 0, 0, 1<<2=x^2, 0, 0, 0, ...]
|
||||
@{[vwsll_vv $V8, $V4, $V6]}
|
||||
|
||||
# Compute [r-IV0*1, r-IV0*x, r-IV0*x^2, r-IV0*x^3, ...] in v16
|
||||
@{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
@{[vbrev8_v $V8, $V8]}
|
||||
@{[vgmul_vv $V16, $V8]}
|
||||
|
||||
# Compute [IV0*1, IV0*x, IV0*x^2, IV0*x^3, ...] in v28.
|
||||
# Reverse the bits order back.
|
||||
@{[vbrev8_v $V28, $V16]}
|
||||
|
||||
# Prepare the x^n multiplier in v20. The `n` is the aes-xts block number
|
||||
# in a LMUL=4 register group.
|
||||
# n = ((VLEN*LMUL)/(32*4)) = ((VLEN*4)/(32*4))
|
||||
# = (VLEN/32)
|
||||
# We could use vsetvli with `e32, m1` to compute the `n` number.
|
||||
@{[vsetvli $T0, "zero", "e32", "m1", "ta", "ma"]}
|
||||
li $T1, 1
|
||||
sll $T0, $T1, $T0
|
||||
@{[vsetivli "zero", 2, "e64", "m1", "ta", "ma"]}
|
||||
@{[vmv_v_i $V0, 0]}
|
||||
@{[vsetivli "zero", 1, "e64", "m1", "tu", "ma"]}
|
||||
@{[vmv_v_x $V0, $T0]}
|
||||
@{[vsetivli "zero", 2, "e64", "m1", "ta", "ma"]}
|
||||
@{[vbrev8_v $V0, $V0]}
|
||||
@{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
@{[vmv_v_i $V20, 0]}
|
||||
@{[vaesz_vs $V20, $V0]}
|
||||
|
||||
j 2f
|
||||
1:
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vbrev8_v $V16, $V28]}
|
||||
2:
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# prepare xts enc last block's input(v24) and iv(v28)
|
||||
sub handle_xts_enc_last_block {
|
||||
my $code=<<___;
|
||||
bnez $TAIL_LENGTH, 1f
|
||||
ret
|
||||
1:
|
||||
# slidedown second to last block
|
||||
addi $VL, $VL, -4
|
||||
@{[vsetivli "zero", 4, "e32", "m4", "ta", "ma"]}
|
||||
# ciphertext
|
||||
@{[vslidedown_vx $V24, $V24, $VL]}
|
||||
# multiplier
|
||||
@{[vslidedown_vx $V16, $V16, $VL]}
|
||||
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vmv_v_v $V25, $V24]}
|
||||
|
||||
# load last block into v24
|
||||
# note: We should load the last block before store the second to last block
|
||||
# for in-place operation.
|
||||
@{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "tu", "ma"]}
|
||||
@{[vle8_v $V24, $INPUT]}
|
||||
|
||||
# setup `x` multiplier with byte-reversed order
|
||||
# 0b00000010 => 0b01000000 (0x40)
|
||||
li $T0, 0x40
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vmv_v_i $V28, 0]}
|
||||
@{[vsetivli "zero", 1, "e8", "m1", "tu", "ma"]}
|
||||
@{[vmv_v_x $V28, $T0]}
|
||||
|
||||
# compute IV for last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vgmul_vv $V16, $V28]}
|
||||
@{[vbrev8_v $V28, $V16]}
|
||||
|
||||
# store second to last block
|
||||
@{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "ta", "ma"]}
|
||||
@{[vse8_v $V25, $OUTPUT]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# prepare xts dec second to last block's input(v24) and iv(v29) and
|
||||
# last block's and iv(v28)
|
||||
sub handle_xts_dec_last_block {
|
||||
my $code=<<___;
|
||||
bnez $TAIL_LENGTH, 1f
|
||||
ret
|
||||
1:
|
||||
# load second to last block's ciphertext
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vle32_v $V24, $INPUT]}
|
||||
addi $INPUT, $INPUT, 16
|
||||
|
||||
# setup `x` multiplier with byte-reversed order
|
||||
# 0b00000010 => 0b01000000 (0x40)
|
||||
li $T0, 0x40
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vmv_v_i $V20, 0]}
|
||||
@{[vsetivli "zero", 1, "e8", "m1", "tu", "ma"]}
|
||||
@{[vmv_v_x $V20, $T0]}
|
||||
|
||||
beqz $LENGTH, 1f
|
||||
# slidedown third to last block
|
||||
addi $VL, $VL, -4
|
||||
@{[vsetivli "zero", 4, "e32", "m4", "ta", "ma"]}
|
||||
# multiplier
|
||||
@{[vslidedown_vx $V16, $V16, $VL]}
|
||||
|
||||
# compute IV for last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vgmul_vv $V16, $V20]}
|
||||
@{[vbrev8_v $V28, $V16]}
|
||||
|
||||
# compute IV for second to last block
|
||||
@{[vgmul_vv $V16, $V20]}
|
||||
@{[vbrev8_v $V29, $V16]}
|
||||
j 2f
|
||||
1:
|
||||
# compute IV for second to last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vgmul_vv $V16, $V20]}
|
||||
@{[vbrev8_v $V29, $V16]}
|
||||
2:
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# Load all 11 round keys to v1-v11 registers.
|
||||
sub aes_128_load_key {
|
||||
my $code=<<___;
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vle32_v $V1, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V2, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V3, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V4, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V5, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V6, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V7, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V8, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V9, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V10, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V11, $KEY1]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# Load all 15 round keys to v1-v15 registers.
|
||||
sub aes_256_load_key {
|
||||
my $code=<<___;
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vle32_v $V1, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V2, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V3, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V4, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V5, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V6, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V7, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V8, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V9, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V10, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V11, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V12, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V13, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V14, $KEY1]}
|
||||
addi $KEY1, $KEY1, 16
|
||||
@{[vle32_v $V15, $KEY1]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# aes-128 enc with round keys v1-v11
|
||||
sub aes_128_enc {
|
||||
my $code=<<___;
|
||||
@{[vaesz_vs $V24, $V1]}
|
||||
@{[vaesem_vs $V24, $V2]}
|
||||
@{[vaesem_vs $V24, $V3]}
|
||||
@{[vaesem_vs $V24, $V4]}
|
||||
@{[vaesem_vs $V24, $V5]}
|
||||
@{[vaesem_vs $V24, $V6]}
|
||||
@{[vaesem_vs $V24, $V7]}
|
||||
@{[vaesem_vs $V24, $V8]}
|
||||
@{[vaesem_vs $V24, $V9]}
|
||||
@{[vaesem_vs $V24, $V10]}
|
||||
@{[vaesef_vs $V24, $V11]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# aes-128 dec with round keys v1-v11
|
||||
sub aes_128_dec {
|
||||
my $code=<<___;
|
||||
@{[vaesz_vs $V24, $V11]}
|
||||
@{[vaesdm_vs $V24, $V10]}
|
||||
@{[vaesdm_vs $V24, $V9]}
|
||||
@{[vaesdm_vs $V24, $V8]}
|
||||
@{[vaesdm_vs $V24, $V7]}
|
||||
@{[vaesdm_vs $V24, $V6]}
|
||||
@{[vaesdm_vs $V24, $V5]}
|
||||
@{[vaesdm_vs $V24, $V4]}
|
||||
@{[vaesdm_vs $V24, $V3]}
|
||||
@{[vaesdm_vs $V24, $V2]}
|
||||
@{[vaesdf_vs $V24, $V1]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# aes-256 enc with round keys v1-v15
|
||||
sub aes_256_enc {
|
||||
my $code=<<___;
|
||||
@{[vaesz_vs $V24, $V1]}
|
||||
@{[vaesem_vs $V24, $V2]}
|
||||
@{[vaesem_vs $V24, $V3]}
|
||||
@{[vaesem_vs $V24, $V4]}
|
||||
@{[vaesem_vs $V24, $V5]}
|
||||
@{[vaesem_vs $V24, $V6]}
|
||||
@{[vaesem_vs $V24, $V7]}
|
||||
@{[vaesem_vs $V24, $V8]}
|
||||
@{[vaesem_vs $V24, $V9]}
|
||||
@{[vaesem_vs $V24, $V10]}
|
||||
@{[vaesem_vs $V24, $V11]}
|
||||
@{[vaesem_vs $V24, $V12]}
|
||||
@{[vaesem_vs $V24, $V13]}
|
||||
@{[vaesem_vs $V24, $V14]}
|
||||
@{[vaesef_vs $V24, $V15]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
# aes-256 dec with round keys v1-v15
|
||||
sub aes_256_dec {
|
||||
my $code=<<___;
|
||||
@{[vaesz_vs $V24, $V15]}
|
||||
@{[vaesdm_vs $V24, $V14]}
|
||||
@{[vaesdm_vs $V24, $V13]}
|
||||
@{[vaesdm_vs $V24, $V12]}
|
||||
@{[vaesdm_vs $V24, $V11]}
|
||||
@{[vaesdm_vs $V24, $V10]}
|
||||
@{[vaesdm_vs $V24, $V9]}
|
||||
@{[vaesdm_vs $V24, $V8]}
|
||||
@{[vaesdm_vs $V24, $V7]}
|
||||
@{[vaesdm_vs $V24, $V6]}
|
||||
@{[vaesdm_vs $V24, $V5]}
|
||||
@{[vaesdm_vs $V24, $V4]}
|
||||
@{[vaesdm_vs $V24, $V3]}
|
||||
@{[vaesdm_vs $V24, $V2]}
|
||||
@{[vaesdf_vs $V24, $V1]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
.globl rv64i_zvbb_zvkg_zvkned_aes_xts_encrypt
|
||||
.type rv64i_zvbb_zvkg_zvkned_aes_xts_encrypt,\@function
|
||||
rv64i_zvbb_zvkg_zvkned_aes_xts_encrypt:
|
||||
@{[compute_xts_iv0]}
|
||||
|
||||
# aes block size is 16
|
||||
andi $TAIL_LENGTH, $LENGTH, 15
|
||||
mv $STORE_LEN32, $LENGTH
|
||||
beqz $TAIL_LENGTH, 1f
|
||||
sub $LENGTH, $LENGTH, $TAIL_LENGTH
|
||||
addi $STORE_LEN32, $LENGTH, -16
|
||||
1:
|
||||
# We make the `LENGTH` become e32 length here.
|
||||
srli $LEN32, $LENGTH, 2
|
||||
srli $STORE_LEN32, $STORE_LEN32, 2
|
||||
|
||||
# Load number of rounds
|
||||
lwu $T0, 240($KEY1)
|
||||
li $T1, 14
|
||||
li $T2, 10
|
||||
beq $T0, $T1, aes_xts_enc_256
|
||||
beq $T0, $T2, aes_xts_enc_128
|
||||
.size rv64i_zvbb_zvkg_zvkned_aes_xts_encrypt,.-rv64i_zvbb_zvkg_zvkned_aes_xts_encrypt
|
||||
___
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
aes_xts_enc_128:
|
||||
@{[init_first_round]}
|
||||
@{[aes_128_load_key]}
|
||||
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
j 1f
|
||||
|
||||
.Lenc_blocks_128:
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
# load plaintext into v24
|
||||
@{[vle32_v $V24, $INPUT]}
|
||||
# update iv
|
||||
@{[vgmul_vv $V16, $V20]}
|
||||
# reverse the iv's bits order back
|
||||
@{[vbrev8_v $V28, $V16]}
|
||||
1:
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
slli $T0, $VL, 2
|
||||
sub $LEN32, $LEN32, $VL
|
||||
add $INPUT, $INPUT, $T0
|
||||
@{[aes_128_enc]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
|
||||
# store ciphertext
|
||||
@{[vsetvli "zero", $STORE_LEN32, "e32", "m4", "ta", "ma"]}
|
||||
@{[vse32_v $V24, $OUTPUT]}
|
||||
add $OUTPUT, $OUTPUT, $T0
|
||||
sub $STORE_LEN32, $STORE_LEN32, $VL
|
||||
|
||||
bnez $LEN32, .Lenc_blocks_128
|
||||
|
||||
@{[handle_xts_enc_last_block]}
|
||||
|
||||
# xts last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
@{[aes_128_enc]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
|
||||
# store last block ciphertext
|
||||
addi $OUTPUT, $OUTPUT, -16
|
||||
@{[vse32_v $V24, $OUTPUT]}
|
||||
|
||||
ret
|
||||
.size aes_xts_enc_128,.-aes_xts_enc_128
|
||||
___
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
aes_xts_enc_256:
|
||||
@{[init_first_round]}
|
||||
@{[aes_256_load_key]}
|
||||
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
j 1f
|
||||
|
||||
.Lenc_blocks_256:
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
# load plaintext into v24
|
||||
@{[vle32_v $V24, $INPUT]}
|
||||
# update iv
|
||||
@{[vgmul_vv $V16, $V20]}
|
||||
# reverse the iv's bits order back
|
||||
@{[vbrev8_v $V28, $V16]}
|
||||
1:
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
slli $T0, $VL, 2
|
||||
sub $LEN32, $LEN32, $VL
|
||||
add $INPUT, $INPUT, $T0
|
||||
@{[aes_256_enc]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
|
||||
# store ciphertext
|
||||
@{[vsetvli "zero", $STORE_LEN32, "e32", "m4", "ta", "ma"]}
|
||||
@{[vse32_v $V24, $OUTPUT]}
|
||||
add $OUTPUT, $OUTPUT, $T0
|
||||
sub $STORE_LEN32, $STORE_LEN32, $VL
|
||||
|
||||
bnez $LEN32, .Lenc_blocks_256
|
||||
|
||||
@{[handle_xts_enc_last_block]}
|
||||
|
||||
# xts last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
@{[aes_256_enc]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
|
||||
# store last block ciphertext
|
||||
addi $OUTPUT, $OUTPUT, -16
|
||||
@{[vse32_v $V24, $OUTPUT]}
|
||||
|
||||
ret
|
||||
.size aes_xts_enc_256,.-aes_xts_enc_256
|
||||
___
|
||||
|
||||
################################################################################
|
||||
# void rv64i_zvbb_zvkg_zvkned_aes_xts_decrypt(const unsigned char *in,
|
||||
# unsigned char *out, size_t length,
|
||||
# const AES_KEY *key1,
|
||||
# const AES_KEY *key2,
|
||||
# const unsigned char iv[16])
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
.globl rv64i_zvbb_zvkg_zvkned_aes_xts_decrypt
|
||||
.type rv64i_zvbb_zvkg_zvkned_aes_xts_decrypt,\@function
|
||||
rv64i_zvbb_zvkg_zvkned_aes_xts_decrypt:
|
||||
@{[compute_xts_iv0]}
|
||||
|
||||
# aes block size is 16
|
||||
andi $TAIL_LENGTH, $LENGTH, 15
|
||||
beqz $TAIL_LENGTH, 1f
|
||||
sub $LENGTH, $LENGTH, $TAIL_LENGTH
|
||||
addi $LENGTH, $LENGTH, -16
|
||||
1:
|
||||
# We make the `LENGTH` become e32 length here.
|
||||
srli $LEN32, $LENGTH, 2
|
||||
|
||||
# Load number of rounds
|
||||
lwu $T0, 240($KEY1)
|
||||
li $T1, 14
|
||||
li $T2, 10
|
||||
beq $T0, $T1, aes_xts_dec_256
|
||||
beq $T0, $T2, aes_xts_dec_128
|
||||
.size rv64i_zvbb_zvkg_zvkned_aes_xts_decrypt,.-rv64i_zvbb_zvkg_zvkned_aes_xts_decrypt
|
||||
___
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
aes_xts_dec_128:
|
||||
@{[init_first_round]}
|
||||
@{[aes_128_load_key]}
|
||||
|
||||
beqz $LEN32, 2f
|
||||
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
j 1f
|
||||
|
||||
.Ldec_blocks_128:
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
# load ciphertext into v24
|
||||
@{[vle32_v $V24, $INPUT]}
|
||||
# update iv
|
||||
@{[vgmul_vv $V16, $V20]}
|
||||
# reverse the iv's bits order back
|
||||
@{[vbrev8_v $V28, $V16]}
|
||||
1:
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
slli $T0, $VL, 2
|
||||
sub $LEN32, $LEN32, $VL
|
||||
add $INPUT, $INPUT, $T0
|
||||
@{[aes_128_dec]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
|
||||
# store plaintext
|
||||
@{[vse32_v $V24, $OUTPUT]}
|
||||
add $OUTPUT, $OUTPUT, $T0
|
||||
|
||||
bnez $LEN32, .Ldec_blocks_128
|
||||
|
||||
2:
|
||||
@{[handle_xts_dec_last_block]}
|
||||
|
||||
## xts second to last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vxor_vv $V24, $V24, $V29]}
|
||||
@{[aes_128_dec]}
|
||||
@{[vxor_vv $V24, $V24, $V29]}
|
||||
@{[vmv_v_v $V25, $V24]}
|
||||
|
||||
# load last block ciphertext
|
||||
@{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "tu", "ma"]}
|
||||
@{[vle8_v $V24, $INPUT]}
|
||||
|
||||
# store second to last block plaintext
|
||||
addi $T0, $OUTPUT, 16
|
||||
@{[vse8_v $V25, $T0]}
|
||||
|
||||
## xts last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
@{[aes_128_dec]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
|
||||
# store second to last block plaintext
|
||||
@{[vse32_v $V24, $OUTPUT]}
|
||||
|
||||
ret
|
||||
.size aes_xts_dec_128,.-aes_xts_dec_128
|
||||
___
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
aes_xts_dec_256:
|
||||
@{[init_first_round]}
|
||||
@{[aes_256_load_key]}
|
||||
|
||||
beqz $LEN32, 2f
|
||||
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
j 1f
|
||||
|
||||
.Ldec_blocks_256:
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
# load ciphertext into v24
|
||||
@{[vle32_v $V24, $INPUT]}
|
||||
# update iv
|
||||
@{[vgmul_vv $V16, $V20]}
|
||||
# reverse the iv's bits order back
|
||||
@{[vbrev8_v $V28, $V16]}
|
||||
1:
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
slli $T0, $VL, 2
|
||||
sub $LEN32, $LEN32, $VL
|
||||
add $INPUT, $INPUT, $T0
|
||||
@{[aes_256_dec]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
|
||||
# store plaintext
|
||||
@{[vse32_v $V24, $OUTPUT]}
|
||||
add $OUTPUT, $OUTPUT, $T0
|
||||
|
||||
bnez $LEN32, .Ldec_blocks_256
|
||||
|
||||
2:
|
||||
@{[handle_xts_dec_last_block]}
|
||||
|
||||
## xts second to last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vxor_vv $V24, $V24, $V29]}
|
||||
@{[aes_256_dec]}
|
||||
@{[vxor_vv $V24, $V24, $V29]}
|
||||
@{[vmv_v_v $V25, $V24]}
|
||||
|
||||
# load last block ciphertext
|
||||
@{[vsetvli "zero", $TAIL_LENGTH, "e8", "m1", "tu", "ma"]}
|
||||
@{[vle8_v $V24, $INPUT]}
|
||||
|
||||
# store second to last block plaintext
|
||||
addi $T0, $OUTPUT, 16
|
||||
@{[vse8_v $V25, $T0]}
|
||||
|
||||
## xts last block
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
@{[aes_256_dec]}
|
||||
@{[vxor_vv $V24, $V24, $V28]}
|
||||
|
||||
# store second to last block plaintext
|
||||
@{[vse32_v $V24, $OUTPUT]}
|
||||
|
||||
ret
|
||||
.size aes_xts_dec_256,.-aes_xts_dec_256
|
||||
___
|
||||
}
|
||||
|
||||
print $code;
|
||||
|
||||
close STDOUT or die "error closing STDOUT: $!";
|
||||
+376
@@ -0,0 +1,376 @@
|
||||
#! /usr/bin/env perl
|
||||
# This file is dual-licensed, meaning that you can use it under your
|
||||
# choice of either of the following two licenses:
|
||||
#
|
||||
# Copyright 2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You can obtain
|
||||
# a copy in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
#
|
||||
# or
|
||||
#
|
||||
# Copyright (c) 2023, Jerry Shih <jerry.shih@sifive.com>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# - RV64I
|
||||
# - RISC-V Vector ('V') with VLEN >= 128
|
||||
# - RISC-V Vector Cryptography Bit-manipulation extension ('Zvkb')
|
||||
# - RISC-V Vector AES block cipher extension ('Zvkned')
|
||||
# - RISC-V Zicclsm(Main memory supports misaligned loads/stores)
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib "$Bin";
|
||||
use lib "$Bin/../../perlasm";
|
||||
use riscv;
|
||||
|
||||
# $output is the last argument if it looks like a file (it has an extension)
|
||||
# $flavour is the first argument if it doesn't look like a file
|
||||
my $output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
|
||||
my $flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
|
||||
|
||||
$output and open STDOUT,">$output";
|
||||
|
||||
my $code=<<___;
|
||||
.text
|
||||
___
|
||||
|
||||
################################################################################
|
||||
# void rv64i_zvkb_zvkned_ctr32_encrypt_blocks(const unsigned char *in,
|
||||
# unsigned char *out, size_t blocks,
|
||||
# const void *key,
|
||||
# const unsigned char ivec[16]);
|
||||
{
|
||||
my ($INP, $OUTP, $BLOCK_NUM, $KEYP, $IVP) = ("a0", "a1", "a2", "a3", "a4");
|
||||
my ($T0, $T1, $T2, $T3) = ("t0", "t1", "t2", "t3");
|
||||
my ($VL) = ("t4");
|
||||
my ($LEN32) = ("t5");
|
||||
my ($CTR) = ("t6");
|
||||
my ($MASK) = ("v0");
|
||||
my ($V0, $V1, $V2, $V3, $V4, $V5, $V6, $V7,
|
||||
$V8, $V9, $V10, $V11, $V12, $V13, $V14, $V15,
|
||||
$V16, $V17, $V18, $V19, $V20, $V21, $V22, $V23,
|
||||
$V24, $V25, $V26, $V27, $V28, $V29, $V30, $V31,
|
||||
) = map("v$_",(0..31));
|
||||
|
||||
# Prepare the AES ctr input data into v16.
|
||||
sub init_aes_ctr_input {
|
||||
my $code=<<___;
|
||||
# Setup mask into v0
|
||||
# The mask pattern for 4*N-th elements
|
||||
# mask v0: [000100010001....]
|
||||
# Note:
|
||||
# We could setup the mask just for the maximum element length instead of
|
||||
# the VLMAX.
|
||||
li $T0, 0b10001000
|
||||
@{[vsetvli $T2, "zero", "e8", "m1", "ta", "ma"]}
|
||||
@{[vmv_v_x $MASK, $T0]}
|
||||
# Load IV.
|
||||
# v31:[IV0, IV1, IV2, big-endian count]
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vle32_v $V31, $IVP]}
|
||||
# Convert the big-endian counter into little-endian.
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "mu"]}
|
||||
@{[vrev8_v $V31, $V31, $MASK]}
|
||||
# Splat the IV to v16
|
||||
@{[vsetvli "zero", $LEN32, "e32", "m4", "ta", "ma"]}
|
||||
@{[vmv_v_i $V16, 0]}
|
||||
@{[vaesz_vs $V16, $V31]}
|
||||
# Prepare the ctr pattern into v20
|
||||
# v20: [x, x, x, 0, x, x, x, 1, x, x, x, 2, ...]
|
||||
@{[viota_m $V20, $MASK, $MASK]}
|
||||
# v16:[IV0, IV1, IV2, count+0, IV0, IV1, IV2, count+1, ...]
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "mu"]}
|
||||
@{[vadd_vv $V16, $V16, $V20, $MASK]}
|
||||
___
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
.globl rv64i_zvkb_zvkned_ctr32_encrypt_blocks
|
||||
.type rv64i_zvkb_zvkned_ctr32_encrypt_blocks,\@function
|
||||
rv64i_zvkb_zvkned_ctr32_encrypt_blocks:
|
||||
beqz $BLOCK_NUM, 1f
|
||||
|
||||
# Load number of rounds
|
||||
lwu $T0, 240($KEYP)
|
||||
li $T1, 14
|
||||
li $T2, 12
|
||||
li $T3, 10
|
||||
|
||||
slli $LEN32, $BLOCK_NUM, 2
|
||||
|
||||
beq $T0, $T1, ctr32_encrypt_blocks_256
|
||||
beq $T0, $T2, ctr32_encrypt_blocks_192
|
||||
beq $T0, $T3, ctr32_encrypt_blocks_128
|
||||
|
||||
1:
|
||||
ret
|
||||
|
||||
.size rv64i_zvkb_zvkned_ctr32_encrypt_blocks,.-rv64i_zvkb_zvkned_ctr32_encrypt_blocks
|
||||
___
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
ctr32_encrypt_blocks_128:
|
||||
# Load all 11 round keys to v1-v11 registers.
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vle32_v $V1, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V2, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V3, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V4, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V5, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V6, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V7, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V8, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V9, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V10, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V11, $KEYP]}
|
||||
|
||||
@{[init_aes_ctr_input]}
|
||||
|
||||
##### AES body
|
||||
j 2f
|
||||
1:
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "mu"]}
|
||||
# Increase ctr in v16.
|
||||
@{[vadd_vx $V16, $V16, $CTR, $MASK]}
|
||||
2:
|
||||
# Load plaintext into v20
|
||||
@{[vle32_v $V20, $INP]}
|
||||
slli $T0, $VL, 2
|
||||
srli $CTR, $VL, 2
|
||||
sub $LEN32, $LEN32, $VL
|
||||
add $INP, $INP, $T0
|
||||
# Prepare the AES ctr input into v24.
|
||||
# The ctr data uses big-endian form.
|
||||
@{[vmv_v_v $V24, $V16]}
|
||||
@{[vrev8_v $V24, $V24, $MASK]}
|
||||
|
||||
@{[vaesz_vs $V24, $V1]}
|
||||
@{[vaesem_vs $V24, $V2]}
|
||||
@{[vaesem_vs $V24, $V3]}
|
||||
@{[vaesem_vs $V24, $V4]}
|
||||
@{[vaesem_vs $V24, $V5]}
|
||||
@{[vaesem_vs $V24, $V6]}
|
||||
@{[vaesem_vs $V24, $V7]}
|
||||
@{[vaesem_vs $V24, $V8]}
|
||||
@{[vaesem_vs $V24, $V9]}
|
||||
@{[vaesem_vs $V24, $V10]}
|
||||
@{[vaesef_vs $V24, $V11]}
|
||||
|
||||
# ciphertext
|
||||
@{[vxor_vv $V24, $V24, $V20]}
|
||||
|
||||
# Store the ciphertext.
|
||||
@{[vse32_v $V24, $OUTP]}
|
||||
add $OUTP, $OUTP, $T0
|
||||
|
||||
bnez $LEN32, 1b
|
||||
|
||||
ret
|
||||
.size ctr32_encrypt_blocks_128,.-ctr32_encrypt_blocks_128
|
||||
___
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
ctr32_encrypt_blocks_192:
|
||||
# Load all 13 round keys to v1-v13 registers.
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vle32_v $V1, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V2, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V3, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V4, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V5, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V6, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V7, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V8, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V9, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V10, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V11, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V12, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V13, $KEYP]}
|
||||
|
||||
@{[init_aes_ctr_input]}
|
||||
|
||||
##### AES body
|
||||
j 2f
|
||||
1:
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "mu"]}
|
||||
# Increase ctr in v16.
|
||||
@{[vadd_vx $V16, $V16, $CTR, $MASK]}
|
||||
2:
|
||||
# Load plaintext into v20
|
||||
@{[vle32_v $V20, $INP]}
|
||||
slli $T0, $VL, 2
|
||||
srli $CTR, $VL, 2
|
||||
sub $LEN32, $LEN32, $VL
|
||||
add $INP, $INP, $T0
|
||||
# Prepare the AES ctr input into v24.
|
||||
# The ctr data uses big-endian form.
|
||||
@{[vmv_v_v $V24, $V16]}
|
||||
@{[vrev8_v $V24, $V24, $MASK]}
|
||||
|
||||
@{[vaesz_vs $V24, $V1]}
|
||||
@{[vaesem_vs $V24, $V2]}
|
||||
@{[vaesem_vs $V24, $V3]}
|
||||
@{[vaesem_vs $V24, $V4]}
|
||||
@{[vaesem_vs $V24, $V5]}
|
||||
@{[vaesem_vs $V24, $V6]}
|
||||
@{[vaesem_vs $V24, $V7]}
|
||||
@{[vaesem_vs $V24, $V8]}
|
||||
@{[vaesem_vs $V24, $V9]}
|
||||
@{[vaesem_vs $V24, $V10]}
|
||||
@{[vaesem_vs $V24, $V11]}
|
||||
@{[vaesem_vs $V24, $V12]}
|
||||
@{[vaesef_vs $V24, $V13]}
|
||||
|
||||
# ciphertext
|
||||
@{[vxor_vv $V24, $V24, $V20]}
|
||||
|
||||
# Store the ciphertext.
|
||||
@{[vse32_v $V24, $OUTP]}
|
||||
add $OUTP, $OUTP, $T0
|
||||
|
||||
bnez $LEN32, 1b
|
||||
|
||||
ret
|
||||
.size ctr32_encrypt_blocks_192,.-ctr32_encrypt_blocks_192
|
||||
___
|
||||
|
||||
$code .= <<___;
|
||||
.p2align 3
|
||||
ctr32_encrypt_blocks_256:
|
||||
# Load all 15 round keys to v1-v15 registers.
|
||||
@{[vsetivli "zero", 4, "e32", "m1", "ta", "ma"]}
|
||||
@{[vle32_v $V1, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V2, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V3, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V4, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V5, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V6, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V7, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V8, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V9, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V10, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V11, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V12, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V13, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V14, $KEYP]}
|
||||
addi $KEYP, $KEYP, 16
|
||||
@{[vle32_v $V15, $KEYP]}
|
||||
|
||||
@{[init_aes_ctr_input]}
|
||||
|
||||
##### AES body
|
||||
j 2f
|
||||
1:
|
||||
@{[vsetvli $VL, $LEN32, "e32", "m4", "ta", "mu"]}
|
||||
# Increase ctr in v16.
|
||||
@{[vadd_vx $V16, $V16, $CTR, $MASK]}
|
||||
2:
|
||||
# Load plaintext into v20
|
||||
@{[vle32_v $V20, $INP]}
|
||||
slli $T0, $VL, 2
|
||||
srli $CTR, $VL, 2
|
||||
sub $LEN32, $LEN32, $VL
|
||||
add $INP, $INP, $T0
|
||||
# Prepare the AES ctr input into v24.
|
||||
# The ctr data uses big-endian form.
|
||||
@{[vmv_v_v $V24, $V16]}
|
||||
@{[vrev8_v $V24, $V24, $MASK]}
|
||||
|
||||
@{[vaesz_vs $V24, $V1]}
|
||||
@{[vaesem_vs $V24, $V2]}
|
||||
@{[vaesem_vs $V24, $V3]}
|
||||
@{[vaesem_vs $V24, $V4]}
|
||||
@{[vaesem_vs $V24, $V5]}
|
||||
@{[vaesem_vs $V24, $V6]}
|
||||
@{[vaesem_vs $V24, $V7]}
|
||||
@{[vaesem_vs $V24, $V8]}
|
||||
@{[vaesem_vs $V24, $V9]}
|
||||
@{[vaesem_vs $V24, $V10]}
|
||||
@{[vaesem_vs $V24, $V11]}
|
||||
@{[vaesem_vs $V24, $V12]}
|
||||
@{[vaesem_vs $V24, $V13]}
|
||||
@{[vaesem_vs $V24, $V14]}
|
||||
@{[vaesef_vs $V24, $V15]}
|
||||
|
||||
# ciphertext
|
||||
@{[vxor_vv $V24, $V24, $V20]}
|
||||
|
||||
# Store the ciphertext.
|
||||
@{[vse32_v $V24, $OUTP]}
|
||||
add $OUTP, $OUTP, $T0
|
||||
|
||||
bnez $LEN32, 1b
|
||||
|
||||
ret
|
||||
.size ctr32_encrypt_blocks_256,.-ctr32_encrypt_blocks_256
|
||||
___
|
||||
}
|
||||
|
||||
print $code;
|
||||
|
||||
close STDOUT or die "error closing STDOUT: $!";
|
||||
+1376
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1272
File diff suppressed because it is too large
Load Diff
+1504
File diff suppressed because it is too large
Load Diff
+2150
File diff suppressed because it is too large
Load Diff
+1806
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+2872
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,931 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2012-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
|
||||
# ====================================================================
|
||||
# Written by David S. Miller and Andy Polyakov.
|
||||
# The module is licensed under 2-clause BSD license. October 2012.
|
||||
# All rights reserved.
|
||||
# ====================================================================
|
||||
|
||||
######################################################################
|
||||
# AES for SPARC T4.
|
||||
#
|
||||
# AES round instructions complete in 3 cycles and can be issued every
|
||||
# cycle. It means that round calculations should take 4*rounds cycles,
|
||||
# because any given round instruction depends on result of *both*
|
||||
# previous instructions:
|
||||
#
|
||||
# |0 |1 |2 |3 |4
|
||||
# |01|01|01|
|
||||
# |23|23|23|
|
||||
# |01|01|...
|
||||
# |23|...
|
||||
#
|
||||
# Provided that fxor [with IV] takes 3 cycles to complete, critical
|
||||
# path length for CBC encrypt would be 3+4*rounds, or in other words
|
||||
# it should process one byte in at least (3+4*rounds)/16 cycles. This
|
||||
# estimate doesn't account for "collateral" instructions, such as
|
||||
# fetching input from memory, xor-ing it with zero-round key and
|
||||
# storing the result. Yet, *measured* performance [for data aligned
|
||||
# at 64-bit boundary!] deviates from this equation by less than 0.5%:
|
||||
#
|
||||
# 128-bit key 192- 256-
|
||||
# CBC encrypt 2.70/2.90(*) 3.20/3.40 3.70/3.90
|
||||
# (*) numbers after slash are for
|
||||
# misaligned data.
|
||||
#
|
||||
# Out-of-order execution logic managed to fully overlap "collateral"
|
||||
# instructions with those on critical path. Amazing!
|
||||
#
|
||||
# As with Intel AES-NI, question is if it's possible to improve
|
||||
# performance of parallelizable modes by interleaving round
|
||||
# instructions. Provided round instruction latency and throughput
|
||||
# optimal interleave factor is 2. But can we expect 2x performance
|
||||
# improvement? Well, as round instructions can be issued one per
|
||||
# cycle, they don't saturate the 2-way issue pipeline and therefore
|
||||
# there is room for "collateral" calculations... Yet, 2x speed-up
|
||||
# over CBC encrypt remains unattaintable:
|
||||
#
|
||||
# 128-bit key 192- 256-
|
||||
# CBC decrypt 1.64/2.11 1.89/2.37 2.23/2.61
|
||||
# CTR 1.64/2.08(*) 1.89/2.33 2.23/2.61
|
||||
# (*) numbers after slash are for
|
||||
# misaligned data.
|
||||
#
|
||||
# Estimates based on amount of instructions under assumption that
|
||||
# round instructions are not pairable with any other instruction
|
||||
# suggest that latter is the actual case and pipeline runs
|
||||
# underutilized. It should be noted that T4 out-of-order execution
|
||||
# logic is so capable that performance gain from 2x interleave is
|
||||
# not even impressive, ~7-13% over non-interleaved code, largest
|
||||
# for 256-bit keys.
|
||||
|
||||
# To anchor to something else, software implementation processes
|
||||
# one byte in 29 cycles with 128-bit key on same processor. Intel
|
||||
# Sandy Bridge encrypts byte in 5.07 cycles in CBC mode and decrypts
|
||||
# in 0.93, naturally with AES-NI.
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "sparcv9_modes.pl";
|
||||
|
||||
$output = pop and open STDOUT,">$output";
|
||||
|
||||
$::evp=1; # if $evp is set to 0, script generates module with
|
||||
# AES_[en|de]crypt, AES_set_[en|de]crypt_key and AES_cbc_encrypt entry
|
||||
# points. These however are not fully compatible with openssl/aes.h,
|
||||
# because they expect AES_KEY to be aligned at 64-bit boundary. When
|
||||
# used through EVP, alignment is arranged at EVP layer. Second thing
|
||||
# that is arranged by EVP is at least 32-bit alignment of IV.
|
||||
|
||||
######################################################################
|
||||
# single-round subroutines
|
||||
#
|
||||
{
|
||||
my ($inp,$out,$key,$rounds,$tmp,$mask)=map("%o$_",(0..5));
|
||||
|
||||
$code.=<<___;
|
||||
#ifndef __ASSEMBLER__
|
||||
# define __ASSEMBLER__ 1
|
||||
#endif
|
||||
#include "crypto/sparc_arch.h"
|
||||
|
||||
#ifdef __arch64__
|
||||
.register %g2,#scratch
|
||||
.register %g3,#scratch
|
||||
#endif
|
||||
|
||||
.text
|
||||
|
||||
.globl aes_t4_encrypt
|
||||
.align 32
|
||||
aes_t4_encrypt:
|
||||
andcc $inp, 7, %g1 ! is input aligned?
|
||||
andn $inp, 7, $inp
|
||||
|
||||
ldx [$key + 0], %g4
|
||||
ldx [$key + 8], %g5
|
||||
|
||||
ldx [$inp + 0], %o4
|
||||
bz,pt %icc, 1f
|
||||
ldx [$inp + 8], %o5
|
||||
ldx [$inp + 16], $inp
|
||||
sll %g1, 3, %g1
|
||||
sub %g0, %g1, %o3
|
||||
sllx %o4, %g1, %o4
|
||||
sllx %o5, %g1, %g1
|
||||
srlx %o5, %o3, %o5
|
||||
srlx $inp, %o3, %o3
|
||||
or %o5, %o4, %o4
|
||||
or %o3, %g1, %o5
|
||||
1:
|
||||
ld [$key + 240], $rounds
|
||||
ldd [$key + 16], %f12
|
||||
ldd [$key + 24], %f14
|
||||
xor %g4, %o4, %o4
|
||||
xor %g5, %o5, %o5
|
||||
movxtod %o4, %f0
|
||||
movxtod %o5, %f2
|
||||
srl $rounds, 1, $rounds
|
||||
ldd [$key + 32], %f16
|
||||
sub $rounds, 1, $rounds
|
||||
ldd [$key + 40], %f18
|
||||
add $key, 48, $key
|
||||
|
||||
.Lenc:
|
||||
aes_eround01 %f12, %f0, %f2, %f4
|
||||
aes_eround23 %f14, %f0, %f2, %f2
|
||||
ldd [$key + 0], %f12
|
||||
ldd [$key + 8], %f14
|
||||
sub $rounds,1,$rounds
|
||||
aes_eround01 %f16, %f4, %f2, %f0
|
||||
aes_eround23 %f18, %f4, %f2, %f2
|
||||
ldd [$key + 16], %f16
|
||||
ldd [$key + 24], %f18
|
||||
brnz,pt $rounds, .Lenc
|
||||
add $key, 32, $key
|
||||
|
||||
andcc $out, 7, $tmp ! is output aligned?
|
||||
aes_eround01 %f12, %f0, %f2, %f4
|
||||
aes_eround23 %f14, %f0, %f2, %f2
|
||||
aes_eround01_l %f16, %f4, %f2, %f0
|
||||
aes_eround23_l %f18, %f4, %f2, %f2
|
||||
|
||||
bnz,pn %icc, 2f
|
||||
nop
|
||||
|
||||
std %f0, [$out + 0]
|
||||
retl
|
||||
std %f2, [$out + 8]
|
||||
|
||||
2: alignaddrl $out, %g0, $out
|
||||
mov 0xff, $mask
|
||||
srl $mask, $tmp, $mask
|
||||
|
||||
faligndata %f0, %f0, %f4
|
||||
faligndata %f0, %f2, %f6
|
||||
faligndata %f2, %f2, %f8
|
||||
|
||||
stda %f4, [$out + $mask]0xc0 ! partial store
|
||||
std %f6, [$out + 8]
|
||||
add $out, 16, $out
|
||||
orn %g0, $mask, $mask
|
||||
retl
|
||||
stda %f8, [$out + $mask]0xc0 ! partial store
|
||||
.type aes_t4_encrypt,#function
|
||||
.size aes_t4_encrypt,.-aes_t4_encrypt
|
||||
|
||||
.globl aes_t4_decrypt
|
||||
.align 32
|
||||
aes_t4_decrypt:
|
||||
andcc $inp, 7, %g1 ! is input aligned?
|
||||
andn $inp, 7, $inp
|
||||
|
||||
ldx [$key + 0], %g4
|
||||
ldx [$key + 8], %g5
|
||||
|
||||
ldx [$inp + 0], %o4
|
||||
bz,pt %icc, 1f
|
||||
ldx [$inp + 8], %o5
|
||||
ldx [$inp + 16], $inp
|
||||
sll %g1, 3, %g1
|
||||
sub %g0, %g1, %o3
|
||||
sllx %o4, %g1, %o4
|
||||
sllx %o5, %g1, %g1
|
||||
srlx %o5, %o3, %o5
|
||||
srlx $inp, %o3, %o3
|
||||
or %o5, %o4, %o4
|
||||
or %o3, %g1, %o5
|
||||
1:
|
||||
ld [$key + 240], $rounds
|
||||
ldd [$key + 16], %f12
|
||||
ldd [$key + 24], %f14
|
||||
xor %g4, %o4, %o4
|
||||
xor %g5, %o5, %o5
|
||||
movxtod %o4, %f0
|
||||
movxtod %o5, %f2
|
||||
srl $rounds, 1, $rounds
|
||||
ldd [$key + 32], %f16
|
||||
sub $rounds, 1, $rounds
|
||||
ldd [$key + 40], %f18
|
||||
add $key, 48, $key
|
||||
|
||||
.Ldec:
|
||||
aes_dround01 %f12, %f0, %f2, %f4
|
||||
aes_dround23 %f14, %f0, %f2, %f2
|
||||
ldd [$key + 0], %f12
|
||||
ldd [$key + 8], %f14
|
||||
sub $rounds,1,$rounds
|
||||
aes_dround01 %f16, %f4, %f2, %f0
|
||||
aes_dround23 %f18, %f4, %f2, %f2
|
||||
ldd [$key + 16], %f16
|
||||
ldd [$key + 24], %f18
|
||||
brnz,pt $rounds, .Ldec
|
||||
add $key, 32, $key
|
||||
|
||||
andcc $out, 7, $tmp ! is output aligned?
|
||||
aes_dround01 %f12, %f0, %f2, %f4
|
||||
aes_dround23 %f14, %f0, %f2, %f2
|
||||
aes_dround01_l %f16, %f4, %f2, %f0
|
||||
aes_dround23_l %f18, %f4, %f2, %f2
|
||||
|
||||
bnz,pn %icc, 2f
|
||||
nop
|
||||
|
||||
std %f0, [$out + 0]
|
||||
retl
|
||||
std %f2, [$out + 8]
|
||||
|
||||
2: alignaddrl $out, %g0, $out
|
||||
mov 0xff, $mask
|
||||
srl $mask, $tmp, $mask
|
||||
|
||||
faligndata %f0, %f0, %f4
|
||||
faligndata %f0, %f2, %f6
|
||||
faligndata %f2, %f2, %f8
|
||||
|
||||
stda %f4, [$out + $mask]0xc0 ! partial store
|
||||
std %f6, [$out + 8]
|
||||
add $out, 16, $out
|
||||
orn %g0, $mask, $mask
|
||||
retl
|
||||
stda %f8, [$out + $mask]0xc0 ! partial store
|
||||
.type aes_t4_decrypt,#function
|
||||
.size aes_t4_decrypt,.-aes_t4_decrypt
|
||||
___
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# key setup subroutines
|
||||
#
|
||||
{
|
||||
my ($inp,$bits,$out,$tmp)=map("%o$_",(0..5));
|
||||
$code.=<<___;
|
||||
.globl aes_t4_set_encrypt_key
|
||||
.align 32
|
||||
aes_t4_set_encrypt_key:
|
||||
.Lset_encrypt_key:
|
||||
and $inp, 7, $tmp
|
||||
alignaddr $inp, %g0, $inp
|
||||
cmp $bits, 192
|
||||
ldd [$inp + 0], %f0
|
||||
bl,pt %icc,.L128
|
||||
ldd [$inp + 8], %f2
|
||||
|
||||
be,pt %icc,.L192
|
||||
ldd [$inp + 16], %f4
|
||||
brz,pt $tmp, .L256aligned
|
||||
ldd [$inp + 24], %f6
|
||||
|
||||
ldd [$inp + 32], %f8
|
||||
faligndata %f0, %f2, %f0
|
||||
faligndata %f2, %f4, %f2
|
||||
faligndata %f4, %f6, %f4
|
||||
faligndata %f6, %f8, %f6
|
||||
.L256aligned:
|
||||
___
|
||||
for ($i=0; $i<6; $i++) {
|
||||
$code.=<<___;
|
||||
std %f0, [$out + `32*$i+0`]
|
||||
aes_kexpand1 %f0, %f6, $i, %f0
|
||||
std %f2, [$out + `32*$i+8`]
|
||||
aes_kexpand2 %f2, %f0, %f2
|
||||
std %f4, [$out + `32*$i+16`]
|
||||
aes_kexpand0 %f4, %f2, %f4
|
||||
std %f6, [$out + `32*$i+24`]
|
||||
aes_kexpand2 %f6, %f4, %f6
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
std %f0, [$out + `32*$i+0`]
|
||||
aes_kexpand1 %f0, %f6, $i, %f0
|
||||
std %f2, [$out + `32*$i+8`]
|
||||
aes_kexpand2 %f2, %f0, %f2
|
||||
std %f4, [$out + `32*$i+16`]
|
||||
std %f6, [$out + `32*$i+24`]
|
||||
std %f0, [$out + `32*$i+32`]
|
||||
std %f2, [$out + `32*$i+40`]
|
||||
|
||||
mov 14, $tmp
|
||||
st $tmp, [$out + 240]
|
||||
retl
|
||||
xor %o0, %o0, %o0
|
||||
|
||||
.align 16
|
||||
.L192:
|
||||
brz,pt $tmp, .L192aligned
|
||||
nop
|
||||
|
||||
ldd [$inp + 24], %f6
|
||||
faligndata %f0, %f2, %f0
|
||||
faligndata %f2, %f4, %f2
|
||||
faligndata %f4, %f6, %f4
|
||||
.L192aligned:
|
||||
___
|
||||
for ($i=0; $i<7; $i++) {
|
||||
$code.=<<___;
|
||||
std %f0, [$out + `24*$i+0`]
|
||||
aes_kexpand1 %f0, %f4, $i, %f0
|
||||
std %f2, [$out + `24*$i+8`]
|
||||
aes_kexpand2 %f2, %f0, %f2
|
||||
std %f4, [$out + `24*$i+16`]
|
||||
aes_kexpand2 %f4, %f2, %f4
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
std %f0, [$out + `24*$i+0`]
|
||||
aes_kexpand1 %f0, %f4, $i, %f0
|
||||
std %f2, [$out + `24*$i+8`]
|
||||
aes_kexpand2 %f2, %f0, %f2
|
||||
std %f4, [$out + `24*$i+16`]
|
||||
std %f0, [$out + `24*$i+24`]
|
||||
std %f2, [$out + `24*$i+32`]
|
||||
|
||||
mov 12, $tmp
|
||||
st $tmp, [$out + 240]
|
||||
retl
|
||||
xor %o0, %o0, %o0
|
||||
|
||||
.align 16
|
||||
.L128:
|
||||
brz,pt $tmp, .L128aligned
|
||||
nop
|
||||
|
||||
ldd [$inp + 16], %f4
|
||||
faligndata %f0, %f2, %f0
|
||||
faligndata %f2, %f4, %f2
|
||||
.L128aligned:
|
||||
___
|
||||
for ($i=0; $i<10; $i++) {
|
||||
$code.=<<___;
|
||||
std %f0, [$out + `16*$i+0`]
|
||||
aes_kexpand1 %f0, %f2, $i, %f0
|
||||
std %f2, [$out + `16*$i+8`]
|
||||
aes_kexpand2 %f2, %f0, %f2
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
std %f0, [$out + `16*$i+0`]
|
||||
std %f2, [$out + `16*$i+8`]
|
||||
|
||||
mov 10, $tmp
|
||||
st $tmp, [$out + 240]
|
||||
retl
|
||||
xor %o0, %o0, %o0
|
||||
.type aes_t4_set_encrypt_key,#function
|
||||
.size aes_t4_set_encrypt_key,.-aes_t4_set_encrypt_key
|
||||
|
||||
.globl aes_t4_set_decrypt_key
|
||||
.align 32
|
||||
aes_t4_set_decrypt_key:
|
||||
mov %o7, %o5
|
||||
call .Lset_encrypt_key
|
||||
nop
|
||||
|
||||
mov %o5, %o7
|
||||
sll $tmp, 4, $inp ! $tmp is number of rounds
|
||||
add $tmp, 2, $tmp
|
||||
add $out, $inp, $inp ! $inp=$out+16*rounds
|
||||
srl $tmp, 2, $tmp ! $tmp=(rounds+2)/4
|
||||
|
||||
.Lkey_flip:
|
||||
ldd [$out + 0], %f0
|
||||
ldd [$out + 8], %f2
|
||||
ldd [$out + 16], %f4
|
||||
ldd [$out + 24], %f6
|
||||
ldd [$inp + 0], %f8
|
||||
ldd [$inp + 8], %f10
|
||||
ldd [$inp - 16], %f12
|
||||
ldd [$inp - 8], %f14
|
||||
sub $tmp, 1, $tmp
|
||||
std %f0, [$inp + 0]
|
||||
std %f2, [$inp + 8]
|
||||
std %f4, [$inp - 16]
|
||||
std %f6, [$inp - 8]
|
||||
std %f8, [$out + 0]
|
||||
std %f10, [$out + 8]
|
||||
std %f12, [$out + 16]
|
||||
std %f14, [$out + 24]
|
||||
add $out, 32, $out
|
||||
brnz $tmp, .Lkey_flip
|
||||
sub $inp, 32, $inp
|
||||
|
||||
retl
|
||||
xor %o0, %o0, %o0
|
||||
.type aes_t4_set_decrypt_key,#function
|
||||
.size aes_t4_set_decrypt_key,.-aes_t4_set_decrypt_key
|
||||
___
|
||||
}
|
||||
|
||||
{{{
|
||||
my ($inp,$out,$len,$key,$ivec,$enc)=map("%i$_",(0..5));
|
||||
my ($ileft,$iright,$ooff,$omask,$ivoff)=map("%l$_",(1..7));
|
||||
|
||||
$code.=<<___;
|
||||
.align 32
|
||||
_aes128_encrypt_1x:
|
||||
___
|
||||
for ($i=0; $i<4; $i++) {
|
||||
$code.=<<___;
|
||||
aes_eround01 %f`16+8*$i+0`, %f0, %f2, %f4
|
||||
aes_eround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+4`, %f4, %f2, %f0
|
||||
aes_eround23 %f`16+8*$i+6`, %f4, %f2, %f2
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_eround01 %f48, %f0, %f2, %f4
|
||||
aes_eround23 %f50, %f0, %f2, %f2
|
||||
aes_eround01_l %f52, %f4, %f2, %f0
|
||||
retl
|
||||
aes_eround23_l %f54, %f4, %f2, %f2
|
||||
.type _aes128_encrypt_1x,#function
|
||||
.size _aes128_encrypt_1x,.-_aes128_encrypt_1x
|
||||
|
||||
.align 32
|
||||
_aes128_encrypt_2x:
|
||||
___
|
||||
for ($i=0; $i<4; $i++) {
|
||||
$code.=<<___;
|
||||
aes_eround01 %f`16+8*$i+0`, %f0, %f2, %f8
|
||||
aes_eround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+0`, %f4, %f6, %f10
|
||||
aes_eround23 %f`16+8*$i+2`, %f4, %f6, %f6
|
||||
aes_eround01 %f`16+8*$i+4`, %f8, %f2, %f0
|
||||
aes_eround23 %f`16+8*$i+6`, %f8, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+4`, %f10, %f6, %f4
|
||||
aes_eround23 %f`16+8*$i+6`, %f10, %f6, %f6
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_eround01 %f48, %f0, %f2, %f8
|
||||
aes_eround23 %f50, %f0, %f2, %f2
|
||||
aes_eround01 %f48, %f4, %f6, %f10
|
||||
aes_eround23 %f50, %f4, %f6, %f6
|
||||
aes_eround01_l %f52, %f8, %f2, %f0
|
||||
aes_eround23_l %f54, %f8, %f2, %f2
|
||||
aes_eround01_l %f52, %f10, %f6, %f4
|
||||
retl
|
||||
aes_eround23_l %f54, %f10, %f6, %f6
|
||||
.type _aes128_encrypt_2x,#function
|
||||
.size _aes128_encrypt_2x,.-_aes128_encrypt_2x
|
||||
|
||||
.align 32
|
||||
_aes128_loadkey:
|
||||
ldx [$key + 0], %g4
|
||||
ldx [$key + 8], %g5
|
||||
___
|
||||
for ($i=2; $i<22;$i++) { # load key schedule
|
||||
$code.=<<___;
|
||||
ldd [$key + `8*$i`], %f`12+2*$i`
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
retl
|
||||
nop
|
||||
.type _aes128_loadkey,#function
|
||||
.size _aes128_loadkey,.-_aes128_loadkey
|
||||
_aes128_load_enckey=_aes128_loadkey
|
||||
_aes128_load_deckey=_aes128_loadkey
|
||||
|
||||
___
|
||||
|
||||
&alg_cbc_encrypt_implement("aes",128);
|
||||
if ($::evp) {
|
||||
&alg_ctr32_implement("aes",128);
|
||||
&alg_xts_implement("aes",128,"en");
|
||||
&alg_xts_implement("aes",128,"de");
|
||||
}
|
||||
&alg_cbc_decrypt_implement("aes",128);
|
||||
|
||||
$code.=<<___;
|
||||
.align 32
|
||||
_aes128_decrypt_1x:
|
||||
___
|
||||
for ($i=0; $i<4; $i++) {
|
||||
$code.=<<___;
|
||||
aes_dround01 %f`16+8*$i+0`, %f0, %f2, %f4
|
||||
aes_dround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+4`, %f4, %f2, %f0
|
||||
aes_dround23 %f`16+8*$i+6`, %f4, %f2, %f2
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_dround01 %f48, %f0, %f2, %f4
|
||||
aes_dround23 %f50, %f0, %f2, %f2
|
||||
aes_dround01_l %f52, %f4, %f2, %f0
|
||||
retl
|
||||
aes_dround23_l %f54, %f4, %f2, %f2
|
||||
.type _aes128_decrypt_1x,#function
|
||||
.size _aes128_decrypt_1x,.-_aes128_decrypt_1x
|
||||
|
||||
.align 32
|
||||
_aes128_decrypt_2x:
|
||||
___
|
||||
for ($i=0; $i<4; $i++) {
|
||||
$code.=<<___;
|
||||
aes_dround01 %f`16+8*$i+0`, %f0, %f2, %f8
|
||||
aes_dround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+0`, %f4, %f6, %f10
|
||||
aes_dround23 %f`16+8*$i+2`, %f4, %f6, %f6
|
||||
aes_dround01 %f`16+8*$i+4`, %f8, %f2, %f0
|
||||
aes_dround23 %f`16+8*$i+6`, %f8, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+4`, %f10, %f6, %f4
|
||||
aes_dround23 %f`16+8*$i+6`, %f10, %f6, %f6
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_dround01 %f48, %f0, %f2, %f8
|
||||
aes_dround23 %f50, %f0, %f2, %f2
|
||||
aes_dround01 %f48, %f4, %f6, %f10
|
||||
aes_dround23 %f50, %f4, %f6, %f6
|
||||
aes_dround01_l %f52, %f8, %f2, %f0
|
||||
aes_dround23_l %f54, %f8, %f2, %f2
|
||||
aes_dround01_l %f52, %f10, %f6, %f4
|
||||
retl
|
||||
aes_dround23_l %f54, %f10, %f6, %f6
|
||||
.type _aes128_decrypt_2x,#function
|
||||
.size _aes128_decrypt_2x,.-_aes128_decrypt_2x
|
||||
___
|
||||
|
||||
$code.=<<___;
|
||||
.align 32
|
||||
_aes192_encrypt_1x:
|
||||
___
|
||||
for ($i=0; $i<5; $i++) {
|
||||
$code.=<<___;
|
||||
aes_eround01 %f`16+8*$i+0`, %f0, %f2, %f4
|
||||
aes_eround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+4`, %f4, %f2, %f0
|
||||
aes_eround23 %f`16+8*$i+6`, %f4, %f2, %f2
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_eround01 %f56, %f0, %f2, %f4
|
||||
aes_eround23 %f58, %f0, %f2, %f2
|
||||
aes_eround01_l %f60, %f4, %f2, %f0
|
||||
retl
|
||||
aes_eround23_l %f62, %f4, %f2, %f2
|
||||
.type _aes192_encrypt_1x,#function
|
||||
.size _aes192_encrypt_1x,.-_aes192_encrypt_1x
|
||||
|
||||
.align 32
|
||||
_aes192_encrypt_2x:
|
||||
___
|
||||
for ($i=0; $i<5; $i++) {
|
||||
$code.=<<___;
|
||||
aes_eround01 %f`16+8*$i+0`, %f0, %f2, %f8
|
||||
aes_eround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+0`, %f4, %f6, %f10
|
||||
aes_eround23 %f`16+8*$i+2`, %f4, %f6, %f6
|
||||
aes_eround01 %f`16+8*$i+4`, %f8, %f2, %f0
|
||||
aes_eround23 %f`16+8*$i+6`, %f8, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+4`, %f10, %f6, %f4
|
||||
aes_eround23 %f`16+8*$i+6`, %f10, %f6, %f6
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_eround01 %f56, %f0, %f2, %f8
|
||||
aes_eround23 %f58, %f0, %f2, %f2
|
||||
aes_eround01 %f56, %f4, %f6, %f10
|
||||
aes_eround23 %f58, %f4, %f6, %f6
|
||||
aes_eround01_l %f60, %f8, %f2, %f0
|
||||
aes_eround23_l %f62, %f8, %f2, %f2
|
||||
aes_eround01_l %f60, %f10, %f6, %f4
|
||||
retl
|
||||
aes_eround23_l %f62, %f10, %f6, %f6
|
||||
.type _aes192_encrypt_2x,#function
|
||||
.size _aes192_encrypt_2x,.-_aes192_encrypt_2x
|
||||
|
||||
.align 32
|
||||
_aes256_encrypt_1x:
|
||||
aes_eround01 %f16, %f0, %f2, %f4
|
||||
aes_eround23 %f18, %f0, %f2, %f2
|
||||
ldd [$key + 208], %f16
|
||||
ldd [$key + 216], %f18
|
||||
aes_eround01 %f20, %f4, %f2, %f0
|
||||
aes_eround23 %f22, %f4, %f2, %f2
|
||||
ldd [$key + 224], %f20
|
||||
ldd [$key + 232], %f22
|
||||
___
|
||||
for ($i=1; $i<6; $i++) {
|
||||
$code.=<<___;
|
||||
aes_eround01 %f`16+8*$i+0`, %f0, %f2, %f4
|
||||
aes_eround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+4`, %f4, %f2, %f0
|
||||
aes_eround23 %f`16+8*$i+6`, %f4, %f2, %f2
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_eround01 %f16, %f0, %f2, %f4
|
||||
aes_eround23 %f18, %f0, %f2, %f2
|
||||
ldd [$key + 16], %f16
|
||||
ldd [$key + 24], %f18
|
||||
aes_eround01_l %f20, %f4, %f2, %f0
|
||||
aes_eround23_l %f22, %f4, %f2, %f2
|
||||
ldd [$key + 32], %f20
|
||||
retl
|
||||
ldd [$key + 40], %f22
|
||||
.type _aes256_encrypt_1x,#function
|
||||
.size _aes256_encrypt_1x,.-_aes256_encrypt_1x
|
||||
|
||||
.align 32
|
||||
_aes256_encrypt_2x:
|
||||
aes_eround01 %f16, %f0, %f2, %f8
|
||||
aes_eround23 %f18, %f0, %f2, %f2
|
||||
aes_eround01 %f16, %f4, %f6, %f10
|
||||
aes_eround23 %f18, %f4, %f6, %f6
|
||||
ldd [$key + 208], %f16
|
||||
ldd [$key + 216], %f18
|
||||
aes_eround01 %f20, %f8, %f2, %f0
|
||||
aes_eround23 %f22, %f8, %f2, %f2
|
||||
aes_eround01 %f20, %f10, %f6, %f4
|
||||
aes_eround23 %f22, %f10, %f6, %f6
|
||||
ldd [$key + 224], %f20
|
||||
ldd [$key + 232], %f22
|
||||
___
|
||||
for ($i=1; $i<6; $i++) {
|
||||
$code.=<<___;
|
||||
aes_eround01 %f`16+8*$i+0`, %f0, %f2, %f8
|
||||
aes_eround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+0`, %f4, %f6, %f10
|
||||
aes_eround23 %f`16+8*$i+2`, %f4, %f6, %f6
|
||||
aes_eround01 %f`16+8*$i+4`, %f8, %f2, %f0
|
||||
aes_eround23 %f`16+8*$i+6`, %f8, %f2, %f2
|
||||
aes_eround01 %f`16+8*$i+4`, %f10, %f6, %f4
|
||||
aes_eround23 %f`16+8*$i+6`, %f10, %f6, %f6
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_eround01 %f16, %f0, %f2, %f8
|
||||
aes_eround23 %f18, %f0, %f2, %f2
|
||||
aes_eround01 %f16, %f4, %f6, %f10
|
||||
aes_eround23 %f18, %f4, %f6, %f6
|
||||
ldd [$key + 16], %f16
|
||||
ldd [$key + 24], %f18
|
||||
aes_eround01_l %f20, %f8, %f2, %f0
|
||||
aes_eround23_l %f22, %f8, %f2, %f2
|
||||
aes_eround01_l %f20, %f10, %f6, %f4
|
||||
aes_eround23_l %f22, %f10, %f6, %f6
|
||||
ldd [$key + 32], %f20
|
||||
retl
|
||||
ldd [$key + 40], %f22
|
||||
.type _aes256_encrypt_2x,#function
|
||||
.size _aes256_encrypt_2x,.-_aes256_encrypt_2x
|
||||
|
||||
.align 32
|
||||
_aes192_loadkey:
|
||||
ldx [$key + 0], %g4
|
||||
ldx [$key + 8], %g5
|
||||
___
|
||||
for ($i=2; $i<26;$i++) { # load key schedule
|
||||
$code.=<<___;
|
||||
ldd [$key + `8*$i`], %f`12+2*$i`
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
retl
|
||||
nop
|
||||
.type _aes192_loadkey,#function
|
||||
.size _aes192_loadkey,.-_aes192_loadkey
|
||||
_aes256_loadkey=_aes192_loadkey
|
||||
_aes192_load_enckey=_aes192_loadkey
|
||||
_aes192_load_deckey=_aes192_loadkey
|
||||
_aes256_load_enckey=_aes192_loadkey
|
||||
_aes256_load_deckey=_aes192_loadkey
|
||||
___
|
||||
|
||||
&alg_cbc_encrypt_implement("aes",256);
|
||||
&alg_cbc_encrypt_implement("aes",192);
|
||||
if ($::evp) {
|
||||
&alg_ctr32_implement("aes",256);
|
||||
&alg_xts_implement("aes",256,"en");
|
||||
&alg_xts_implement("aes",256,"de");
|
||||
&alg_ctr32_implement("aes",192);
|
||||
}
|
||||
&alg_cbc_decrypt_implement("aes",192);
|
||||
&alg_cbc_decrypt_implement("aes",256);
|
||||
|
||||
$code.=<<___;
|
||||
.align 32
|
||||
_aes256_decrypt_1x:
|
||||
aes_dround01 %f16, %f0, %f2, %f4
|
||||
aes_dround23 %f18, %f0, %f2, %f2
|
||||
ldd [$key + 208], %f16
|
||||
ldd [$key + 216], %f18
|
||||
aes_dround01 %f20, %f4, %f2, %f0
|
||||
aes_dround23 %f22, %f4, %f2, %f2
|
||||
ldd [$key + 224], %f20
|
||||
ldd [$key + 232], %f22
|
||||
___
|
||||
for ($i=1; $i<6; $i++) {
|
||||
$code.=<<___;
|
||||
aes_dround01 %f`16+8*$i+0`, %f0, %f2, %f4
|
||||
aes_dround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+4`, %f4, %f2, %f0
|
||||
aes_dround23 %f`16+8*$i+6`, %f4, %f2, %f2
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_dround01 %f16, %f0, %f2, %f4
|
||||
aes_dround23 %f18, %f0, %f2, %f2
|
||||
ldd [$key + 16], %f16
|
||||
ldd [$key + 24], %f18
|
||||
aes_dround01_l %f20, %f4, %f2, %f0
|
||||
aes_dround23_l %f22, %f4, %f2, %f2
|
||||
ldd [$key + 32], %f20
|
||||
retl
|
||||
ldd [$key + 40], %f22
|
||||
.type _aes256_decrypt_1x,#function
|
||||
.size _aes256_decrypt_1x,.-_aes256_decrypt_1x
|
||||
|
||||
.align 32
|
||||
_aes256_decrypt_2x:
|
||||
aes_dround01 %f16, %f0, %f2, %f8
|
||||
aes_dround23 %f18, %f0, %f2, %f2
|
||||
aes_dround01 %f16, %f4, %f6, %f10
|
||||
aes_dround23 %f18, %f4, %f6, %f6
|
||||
ldd [$key + 208], %f16
|
||||
ldd [$key + 216], %f18
|
||||
aes_dround01 %f20, %f8, %f2, %f0
|
||||
aes_dround23 %f22, %f8, %f2, %f2
|
||||
aes_dround01 %f20, %f10, %f6, %f4
|
||||
aes_dround23 %f22, %f10, %f6, %f6
|
||||
ldd [$key + 224], %f20
|
||||
ldd [$key + 232], %f22
|
||||
___
|
||||
for ($i=1; $i<6; $i++) {
|
||||
$code.=<<___;
|
||||
aes_dround01 %f`16+8*$i+0`, %f0, %f2, %f8
|
||||
aes_dround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+0`, %f4, %f6, %f10
|
||||
aes_dround23 %f`16+8*$i+2`, %f4, %f6, %f6
|
||||
aes_dround01 %f`16+8*$i+4`, %f8, %f2, %f0
|
||||
aes_dround23 %f`16+8*$i+6`, %f8, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+4`, %f10, %f6, %f4
|
||||
aes_dround23 %f`16+8*$i+6`, %f10, %f6, %f6
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_dround01 %f16, %f0, %f2, %f8
|
||||
aes_dround23 %f18, %f0, %f2, %f2
|
||||
aes_dround01 %f16, %f4, %f6, %f10
|
||||
aes_dround23 %f18, %f4, %f6, %f6
|
||||
ldd [$key + 16], %f16
|
||||
ldd [$key + 24], %f18
|
||||
aes_dround01_l %f20, %f8, %f2, %f0
|
||||
aes_dround23_l %f22, %f8, %f2, %f2
|
||||
aes_dround01_l %f20, %f10, %f6, %f4
|
||||
aes_dround23_l %f22, %f10, %f6, %f6
|
||||
ldd [$key + 32], %f20
|
||||
retl
|
||||
ldd [$key + 40], %f22
|
||||
.type _aes256_decrypt_2x,#function
|
||||
.size _aes256_decrypt_2x,.-_aes256_decrypt_2x
|
||||
|
||||
.align 32
|
||||
_aes192_decrypt_1x:
|
||||
___
|
||||
for ($i=0; $i<5; $i++) {
|
||||
$code.=<<___;
|
||||
aes_dround01 %f`16+8*$i+0`, %f0, %f2, %f4
|
||||
aes_dround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+4`, %f4, %f2, %f0
|
||||
aes_dround23 %f`16+8*$i+6`, %f4, %f2, %f2
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_dround01 %f56, %f0, %f2, %f4
|
||||
aes_dround23 %f58, %f0, %f2, %f2
|
||||
aes_dround01_l %f60, %f4, %f2, %f0
|
||||
retl
|
||||
aes_dround23_l %f62, %f4, %f2, %f2
|
||||
.type _aes192_decrypt_1x,#function
|
||||
.size _aes192_decrypt_1x,.-_aes192_decrypt_1x
|
||||
|
||||
.align 32
|
||||
_aes192_decrypt_2x:
|
||||
___
|
||||
for ($i=0; $i<5; $i++) {
|
||||
$code.=<<___;
|
||||
aes_dround01 %f`16+8*$i+0`, %f0, %f2, %f8
|
||||
aes_dround23 %f`16+8*$i+2`, %f0, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+0`, %f4, %f6, %f10
|
||||
aes_dround23 %f`16+8*$i+2`, %f4, %f6, %f6
|
||||
aes_dround01 %f`16+8*$i+4`, %f8, %f2, %f0
|
||||
aes_dround23 %f`16+8*$i+6`, %f8, %f2, %f2
|
||||
aes_dround01 %f`16+8*$i+4`, %f10, %f6, %f4
|
||||
aes_dround23 %f`16+8*$i+6`, %f10, %f6, %f6
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
aes_dround01 %f56, %f0, %f2, %f8
|
||||
aes_dround23 %f58, %f0, %f2, %f2
|
||||
aes_dround01 %f56, %f4, %f6, %f10
|
||||
aes_dround23 %f58, %f4, %f6, %f6
|
||||
aes_dround01_l %f60, %f8, %f2, %f0
|
||||
aes_dround23_l %f62, %f8, %f2, %f2
|
||||
aes_dround01_l %f60, %f10, %f6, %f4
|
||||
retl
|
||||
aes_dround23_l %f62, %f10, %f6, %f6
|
||||
.type _aes192_decrypt_2x,#function
|
||||
.size _aes192_decrypt_2x,.-_aes192_decrypt_2x
|
||||
___
|
||||
}}}
|
||||
|
||||
if (!$::evp) {
|
||||
$code.=<<___;
|
||||
.global AES_encrypt
|
||||
AES_encrypt=aes_t4_encrypt
|
||||
.global AES_decrypt
|
||||
AES_decrypt=aes_t4_decrypt
|
||||
.global AES_set_encrypt_key
|
||||
.align 32
|
||||
AES_set_encrypt_key:
|
||||
andcc %o2, 7, %g0 ! check alignment
|
||||
bnz,a,pn %icc, 1f
|
||||
mov -1, %o0
|
||||
brz,a,pn %o0, 1f
|
||||
mov -1, %o0
|
||||
brz,a,pn %o2, 1f
|
||||
mov -1, %o0
|
||||
andncc %o1, 0x1c0, %g0
|
||||
bnz,a,pn %icc, 1f
|
||||
mov -2, %o0
|
||||
cmp %o1, 128
|
||||
bl,a,pn %icc, 1f
|
||||
mov -2, %o0
|
||||
b aes_t4_set_encrypt_key
|
||||
nop
|
||||
1: retl
|
||||
nop
|
||||
.type AES_set_encrypt_key,#function
|
||||
.size AES_set_encrypt_key,.-AES_set_encrypt_key
|
||||
|
||||
.global AES_set_decrypt_key
|
||||
.align 32
|
||||
AES_set_decrypt_key:
|
||||
andcc %o2, 7, %g0 ! check alignment
|
||||
bnz,a,pn %icc, 1f
|
||||
mov -1, %o0
|
||||
brz,a,pn %o0, 1f
|
||||
mov -1, %o0
|
||||
brz,a,pn %o2, 1f
|
||||
mov -1, %o0
|
||||
andncc %o1, 0x1c0, %g0
|
||||
bnz,a,pn %icc, 1f
|
||||
mov -2, %o0
|
||||
cmp %o1, 128
|
||||
bl,a,pn %icc, 1f
|
||||
mov -2, %o0
|
||||
b aes_t4_set_decrypt_key
|
||||
nop
|
||||
1: retl
|
||||
nop
|
||||
.type AES_set_decrypt_key,#function
|
||||
.size AES_set_decrypt_key,.-AES_set_decrypt_key
|
||||
___
|
||||
|
||||
my ($inp,$out,$len,$key,$ivec,$enc)=map("%o$_",(0..5));
|
||||
|
||||
$code.=<<___;
|
||||
.globl AES_cbc_encrypt
|
||||
.align 32
|
||||
AES_cbc_encrypt:
|
||||
ld [$key + 240], %g1
|
||||
nop
|
||||
brz $enc, .Lcbc_decrypt
|
||||
cmp %g1, 12
|
||||
|
||||
bl,pt %icc, aes128_t4_cbc_encrypt
|
||||
nop
|
||||
be,pn %icc, aes192_t4_cbc_encrypt
|
||||
nop
|
||||
ba aes256_t4_cbc_encrypt
|
||||
nop
|
||||
|
||||
.Lcbc_decrypt:
|
||||
bl,pt %icc, aes128_t4_cbc_decrypt
|
||||
nop
|
||||
be,pn %icc, aes192_t4_cbc_decrypt
|
||||
nop
|
||||
ba aes256_t4_cbc_decrypt
|
||||
nop
|
||||
.type AES_cbc_encrypt,#function
|
||||
.size AES_cbc_encrypt,.-AES_cbc_encrypt
|
||||
___
|
||||
}
|
||||
$code.=<<___;
|
||||
.asciz "AES for SPARC T4, David S. Miller, Andy Polyakov"
|
||||
.align 4
|
||||
___
|
||||
|
||||
&emit_assembler();
|
||||
|
||||
close STDOUT or die "error closing STDOUT: $!";
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1004
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,914 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
|
||||
######################################################################
|
||||
## Constant-time SSSE3 AES core implementation.
|
||||
## version 0.1
|
||||
##
|
||||
## By Mike Hamburg (Stanford University), 2009
|
||||
## Public domain.
|
||||
##
|
||||
## For details see http://shiftleft.org/papers/vector_aes/ and
|
||||
## http://crypto.stanford.edu/vpaes/.
|
||||
|
||||
######################################################################
|
||||
# September 2011.
|
||||
#
|
||||
# Port vpaes-x86_64.pl as 32-bit "almost" drop-in replacement for
|
||||
# aes-586.pl. "Almost" refers to the fact that AES_cbc_encrypt
|
||||
# doesn't handle partial vectors (doesn't have to if called from
|
||||
# EVP only). "Drop-in" implies that this module doesn't share key
|
||||
# schedule structure with the original nor does it make assumption
|
||||
# about its alignment...
|
||||
#
|
||||
# Performance summary. aes-586.pl column lists large-block CBC
|
||||
# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per
|
||||
# byte processed with 128-bit key, and vpaes-x86.pl column - [also
|
||||
# large-block CBC] encrypt/decrypt.
|
||||
#
|
||||
# aes-586.pl vpaes-x86.pl
|
||||
#
|
||||
# Core 2(**) 28.1/41.4/18.3 21.9/25.2(***)
|
||||
# Nehalem 27.9/40.4/18.1 10.2/11.9
|
||||
# Atom 70.7/92.1/60.1 61.1/75.4(***)
|
||||
# Silvermont 45.4/62.9/24.1 49.2/61.1(***)
|
||||
#
|
||||
# (*) "Hyper-threading" in the context refers rather to cache shared
|
||||
# among multiple cores, than to specifically Intel HTT. As vast
|
||||
# majority of contemporary cores share cache, slower code path
|
||||
# is common place. In other words "with-hyper-threading-off"
|
||||
# results are presented mostly for reference purposes.
|
||||
#
|
||||
# (**) "Core 2" refers to initial 65nm design, a.k.a. Conroe.
|
||||
#
|
||||
# (***) Less impressive improvement on Core 2 and Atom is due to slow
|
||||
# pshufb, yet it's respectable +28%/64% improvement on Core 2
|
||||
# and +15% on Atom (as implied, over "hyper-threading-safe"
|
||||
# code path).
|
||||
#
|
||||
# <appro@openssl.org>
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
push(@INC,"${dir}","${dir}../../perlasm");
|
||||
require "x86asm.pl";
|
||||
|
||||
$output = pop and open STDOUT,">$output";
|
||||
|
||||
&asm_init($ARGV[0],$x86only = $ARGV[$#ARGV] eq "386");
|
||||
|
||||
$PREFIX="vpaes";
|
||||
|
||||
my ($round, $base, $magic, $key, $const, $inp, $out)=
|
||||
("eax", "ebx", "ecx", "edx","ebp", "esi","edi");
|
||||
|
||||
&static_label("_vpaes_consts");
|
||||
&static_label("_vpaes_schedule_low_round");
|
||||
|
||||
&set_label("_vpaes_consts",64);
|
||||
$k_inv=-0x30; # inv, inva
|
||||
&data_word(0x0D080180,0x0E05060F,0x0A0B0C02,0x04070309);
|
||||
&data_word(0x0F0B0780,0x01040A06,0x02050809,0x030D0E0C);
|
||||
|
||||
$k_s0F=-0x10; # s0F
|
||||
&data_word(0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F);
|
||||
|
||||
$k_ipt=0x00; # input transform (lo, hi)
|
||||
&data_word(0x5A2A7000,0xC2B2E898,0x52227808,0xCABAE090);
|
||||
&data_word(0x317C4D00,0x4C01307D,0xB0FDCC81,0xCD80B1FC);
|
||||
|
||||
$k_sb1=0x20; # sb1u, sb1t
|
||||
&data_word(0xCB503E00,0xB19BE18F,0x142AF544,0xA5DF7A6E);
|
||||
&data_word(0xFAE22300,0x3618D415,0x0D2ED9EF,0x3BF7CCC1);
|
||||
$k_sb2=0x40; # sb2u, sb2t
|
||||
&data_word(0x0B712400,0xE27A93C6,0xBC982FCD,0x5EB7E955);
|
||||
&data_word(0x0AE12900,0x69EB8840,0xAB82234A,0xC2A163C8);
|
||||
$k_sbo=0x60; # sbou, sbot
|
||||
&data_word(0x6FBDC700,0xD0D26D17,0xC502A878,0x15AABF7A);
|
||||
&data_word(0x5FBB6A00,0xCFE474A5,0x412B35FA,0x8E1E90D1);
|
||||
|
||||
$k_mc_forward=0x80; # mc_forward
|
||||
&data_word(0x00030201,0x04070605,0x080B0A09,0x0C0F0E0D);
|
||||
&data_word(0x04070605,0x080B0A09,0x0C0F0E0D,0x00030201);
|
||||
&data_word(0x080B0A09,0x0C0F0E0D,0x00030201,0x04070605);
|
||||
&data_word(0x0C0F0E0D,0x00030201,0x04070605,0x080B0A09);
|
||||
|
||||
$k_mc_backward=0xc0; # mc_backward
|
||||
&data_word(0x02010003,0x06050407,0x0A09080B,0x0E0D0C0F);
|
||||
&data_word(0x0E0D0C0F,0x02010003,0x06050407,0x0A09080B);
|
||||
&data_word(0x0A09080B,0x0E0D0C0F,0x02010003,0x06050407);
|
||||
&data_word(0x06050407,0x0A09080B,0x0E0D0C0F,0x02010003);
|
||||
|
||||
$k_sr=0x100; # sr
|
||||
&data_word(0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C);
|
||||
&data_word(0x0F0A0500,0x030E0904,0x07020D08,0x0B06010C);
|
||||
&data_word(0x0B020900,0x0F060D04,0x030A0108,0x070E050C);
|
||||
&data_word(0x070A0D00,0x0B0E0104,0x0F020508,0x0306090C);
|
||||
|
||||
$k_rcon=0x140; # rcon
|
||||
&data_word(0xAF9DEEB6,0x1F8391B9,0x4D7C7D81,0x702A9808);
|
||||
|
||||
$k_s63=0x150; # s63: all equal to 0x63 transformed
|
||||
&data_word(0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B);
|
||||
|
||||
$k_opt=0x160; # output transform
|
||||
&data_word(0xD6B66000,0xFF9F4929,0xDEBE6808,0xF7974121);
|
||||
&data_word(0x50BCEC00,0x01EDBD51,0xB05C0CE0,0xE10D5DB1);
|
||||
|
||||
$k_deskew=0x180; # deskew tables: inverts the sbox's "skew"
|
||||
&data_word(0x47A4E300,0x07E4A340,0x5DBEF91A,0x1DFEB95A);
|
||||
&data_word(0x83EA6900,0x5F36B5DC,0xF49D1E77,0x2841C2AB);
|
||||
##
|
||||
## Decryption stuff
|
||||
## Key schedule constants
|
||||
##
|
||||
$k_dksd=0x1a0; # decryption key schedule: invskew x*D
|
||||
&data_word(0xA3E44700,0xFEB91A5D,0x5A1DBEF9,0x0740E3A4);
|
||||
&data_word(0xB5368300,0x41C277F4,0xAB289D1E,0x5FDC69EA);
|
||||
$k_dksb=0x1c0; # decryption key schedule: invskew x*B
|
||||
&data_word(0x8550D500,0x9A4FCA1F,0x1CC94C99,0x03D65386);
|
||||
&data_word(0xB6FC4A00,0x115BEDA7,0x7E3482C8,0xD993256F);
|
||||
$k_dkse=0x1e0; # decryption key schedule: invskew x*E + 0x63
|
||||
&data_word(0x1FC9D600,0xD5031CCA,0x994F5086,0x53859A4C);
|
||||
&data_word(0x4FDC7BE8,0xA2319605,0x20B31487,0xCD5EF96A);
|
||||
$k_dks9=0x200; # decryption key schedule: invskew x*9
|
||||
&data_word(0x7ED9A700,0xB6116FC8,0x82255BFC,0x4AED9334);
|
||||
&data_word(0x27143300,0x45765162,0xE9DAFDCE,0x8BB89FAC);
|
||||
|
||||
##
|
||||
## Decryption stuff
|
||||
## Round function constants
|
||||
##
|
||||
$k_dipt=0x220; # decryption input transform
|
||||
&data_word(0x0B545F00,0x0F505B04,0x114E451A,0x154A411E);
|
||||
&data_word(0x60056500,0x86E383E6,0xF491F194,0x12771772);
|
||||
|
||||
$k_dsb9=0x240; # decryption sbox output *9*u, *9*t
|
||||
&data_word(0x9A86D600,0x851C0353,0x4F994CC9,0xCAD51F50);
|
||||
&data_word(0xECD74900,0xC03B1789,0xB2FBA565,0x725E2C9E);
|
||||
$k_dsbd=0x260; # decryption sbox output *D*u, *D*t
|
||||
&data_word(0xE6B1A200,0x7D57CCDF,0x882A4439,0xF56E9B13);
|
||||
&data_word(0x24C6CB00,0x3CE2FAF7,0x15DEEFD3,0x2931180D);
|
||||
$k_dsbb=0x280; # decryption sbox output *B*u, *B*t
|
||||
&data_word(0x96B44200,0xD0226492,0xB0F2D404,0x602646F6);
|
||||
&data_word(0xCD596700,0xC19498A6,0x3255AA6B,0xF3FF0C3E);
|
||||
$k_dsbe=0x2a0; # decryption sbox output *E*u, *E*t
|
||||
&data_word(0x26D4D000,0x46F29296,0x64B4F6B0,0x22426004);
|
||||
&data_word(0xFFAAC100,0x0C55A6CD,0x98593E32,0x9467F36B);
|
||||
$k_dsbo=0x2c0; # decryption sbox final output
|
||||
&data_word(0x7EF94000,0x1387EA53,0xD4943E2D,0xC7AA6DB9);
|
||||
&data_word(0x93441D00,0x12D7560F,0xD8C58E9C,0xCA4B8159);
|
||||
&asciz ("Vector Permutation AES for x86/SSSE3, Mike Hamburg (Stanford University)");
|
||||
&align (64);
|
||||
|
||||
&function_begin_B("_vpaes_preheat");
|
||||
&add ($const,&DWP(0,"esp"));
|
||||
&movdqa ("xmm7",&QWP($k_inv,$const));
|
||||
&movdqa ("xmm6",&QWP($k_s0F,$const));
|
||||
&ret ();
|
||||
&function_end_B("_vpaes_preheat");
|
||||
|
||||
##
|
||||
## _aes_encrypt_core
|
||||
##
|
||||
## AES-encrypt %xmm0.
|
||||
##
|
||||
## Inputs:
|
||||
## %xmm0 = input
|
||||
## %xmm6-%xmm7 as in _vpaes_preheat
|
||||
## (%edx) = scheduled keys
|
||||
##
|
||||
## Output in %xmm0
|
||||
## Clobbers %xmm1-%xmm5, %eax, %ebx, %ecx, %edx
|
||||
##
|
||||
##
|
||||
&function_begin_B("_vpaes_encrypt_core");
|
||||
&mov ($magic,16);
|
||||
&mov ($round,&DWP(240,$key));
|
||||
&movdqa ("xmm1","xmm6")
|
||||
&movdqa ("xmm2",&QWP($k_ipt,$const));
|
||||
&pandn ("xmm1","xmm0");
|
||||
&pand ("xmm0","xmm6");
|
||||
&movdqu ("xmm5",&QWP(0,$key));
|
||||
&pshufb ("xmm2","xmm0");
|
||||
&movdqa ("xmm0",&QWP($k_ipt+16,$const));
|
||||
&pxor ("xmm2","xmm5");
|
||||
&psrld ("xmm1",4);
|
||||
&add ($key,16);
|
||||
&pshufb ("xmm0","xmm1");
|
||||
&lea ($base,&DWP($k_mc_backward,$const));
|
||||
&pxor ("xmm0","xmm2");
|
||||
&jmp (&label("enc_entry"));
|
||||
|
||||
|
||||
&set_label("enc_loop",16);
|
||||
# middle of middle round
|
||||
&movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sb1u
|
||||
&movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sb1t
|
||||
&pshufb ("xmm4","xmm2"); # 4 = sb1u
|
||||
&pshufb ("xmm0","xmm3"); # 0 = sb1t
|
||||
&pxor ("xmm4","xmm5"); # 4 = sb1u + k
|
||||
&movdqa ("xmm5",&QWP($k_sb2,$const)); # 4 : sb2u
|
||||
&pxor ("xmm0","xmm4"); # 0 = A
|
||||
&movdqa ("xmm1",&QWP(-0x40,$base,$magic));# .Lk_mc_forward[]
|
||||
&pshufb ("xmm5","xmm2"); # 4 = sb2u
|
||||
&movdqa ("xmm2",&QWP($k_sb2+16,$const));# 2 : sb2t
|
||||
&movdqa ("xmm4",&QWP(0,$base,$magic)); # .Lk_mc_backward[]
|
||||
&pshufb ("xmm2","xmm3"); # 2 = sb2t
|
||||
&movdqa ("xmm3","xmm0"); # 3 = A
|
||||
&pxor ("xmm2","xmm5"); # 2 = 2A
|
||||
&pshufb ("xmm0","xmm1"); # 0 = B
|
||||
&add ($key,16); # next key
|
||||
&pxor ("xmm0","xmm2"); # 0 = 2A+B
|
||||
&pshufb ("xmm3","xmm4"); # 3 = D
|
||||
&add ($magic,16); # next mc
|
||||
&pxor ("xmm3","xmm0"); # 3 = 2A+B+D
|
||||
&pshufb ("xmm0","xmm1"); # 0 = 2B+C
|
||||
&and ($magic,0x30); # ... mod 4
|
||||
&sub ($round,1); # nr--
|
||||
&pxor ("xmm0","xmm3"); # 0 = 2A+3B+C+D
|
||||
|
||||
&set_label("enc_entry");
|
||||
# top of round
|
||||
&movdqa ("xmm1","xmm6"); # 1 : i
|
||||
&movdqa ("xmm5",&QWP($k_inv+16,$const));# 2 : a/k
|
||||
&pandn ("xmm1","xmm0"); # 1 = i<<4
|
||||
&psrld ("xmm1",4); # 1 = i
|
||||
&pand ("xmm0","xmm6"); # 0 = k
|
||||
&pshufb ("xmm5","xmm0"); # 2 = a/k
|
||||
&movdqa ("xmm3","xmm7"); # 3 : 1/i
|
||||
&pxor ("xmm0","xmm1"); # 0 = j
|
||||
&pshufb ("xmm3","xmm1"); # 3 = 1/i
|
||||
&movdqa ("xmm4","xmm7"); # 4 : 1/j
|
||||
&pxor ("xmm3","xmm5"); # 3 = iak = 1/i + a/k
|
||||
&pshufb ("xmm4","xmm0"); # 4 = 1/j
|
||||
&movdqa ("xmm2","xmm7"); # 2 : 1/iak
|
||||
&pxor ("xmm4","xmm5"); # 4 = jak = 1/j + a/k
|
||||
&pshufb ("xmm2","xmm3"); # 2 = 1/iak
|
||||
&movdqa ("xmm3","xmm7"); # 3 : 1/jak
|
||||
&pxor ("xmm2","xmm0"); # 2 = io
|
||||
&pshufb ("xmm3","xmm4"); # 3 = 1/jak
|
||||
&movdqu ("xmm5",&QWP(0,$key));
|
||||
&pxor ("xmm3","xmm1"); # 3 = jo
|
||||
&jnz (&label("enc_loop"));
|
||||
|
||||
# middle of last round
|
||||
&movdqa ("xmm4",&QWP($k_sbo,$const)); # 3 : sbou .Lk_sbo
|
||||
&movdqa ("xmm0",&QWP($k_sbo+16,$const));# 3 : sbot .Lk_sbo+16
|
||||
&pshufb ("xmm4","xmm2"); # 4 = sbou
|
||||
&pxor ("xmm4","xmm5"); # 4 = sb1u + k
|
||||
&pshufb ("xmm0","xmm3"); # 0 = sb1t
|
||||
&movdqa ("xmm1",&QWP(0x40,$base,$magic));# .Lk_sr[]
|
||||
&pxor ("xmm0","xmm4"); # 0 = A
|
||||
&pshufb ("xmm0","xmm1");
|
||||
&ret ();
|
||||
&function_end_B("_vpaes_encrypt_core");
|
||||
|
||||
##
|
||||
## Decryption core
|
||||
##
|
||||
## Same API as encryption core.
|
||||
##
|
||||
&function_begin_B("_vpaes_decrypt_core");
|
||||
&lea ($base,&DWP($k_dsbd,$const));
|
||||
&mov ($round,&DWP(240,$key));
|
||||
&movdqa ("xmm1","xmm6");
|
||||
&movdqa ("xmm2",&QWP($k_dipt-$k_dsbd,$base));
|
||||
&pandn ("xmm1","xmm0");
|
||||
&mov ($magic,$round);
|
||||
&psrld ("xmm1",4)
|
||||
&movdqu ("xmm5",&QWP(0,$key));
|
||||
&shl ($magic,4);
|
||||
&pand ("xmm0","xmm6");
|
||||
&pshufb ("xmm2","xmm0");
|
||||
&movdqa ("xmm0",&QWP($k_dipt-$k_dsbd+16,$base));
|
||||
&xor ($magic,0x30);
|
||||
&pshufb ("xmm0","xmm1");
|
||||
&and ($magic,0x30);
|
||||
&pxor ("xmm2","xmm5");
|
||||
&movdqa ("xmm5",&QWP($k_mc_forward+48,$const));
|
||||
&pxor ("xmm0","xmm2");
|
||||
&add ($key,16);
|
||||
&lea ($magic,&DWP($k_sr-$k_dsbd,$base,$magic));
|
||||
&jmp (&label("dec_entry"));
|
||||
|
||||
&set_label("dec_loop",16);
|
||||
##
|
||||
## Inverse mix columns
|
||||
##
|
||||
&movdqa ("xmm4",&QWP(-0x20,$base)); # 4 : sb9u
|
||||
&movdqa ("xmm1",&QWP(-0x10,$base)); # 0 : sb9t
|
||||
&pshufb ("xmm4","xmm2"); # 4 = sb9u
|
||||
&pshufb ("xmm1","xmm3"); # 0 = sb9t
|
||||
&pxor ("xmm0","xmm4");
|
||||
&movdqa ("xmm4",&QWP(0,$base)); # 4 : sbdu
|
||||
&pxor ("xmm0","xmm1"); # 0 = ch
|
||||
&movdqa ("xmm1",&QWP(0x10,$base)); # 0 : sbdt
|
||||
|
||||
&pshufb ("xmm4","xmm2"); # 4 = sbdu
|
||||
&pshufb ("xmm0","xmm5"); # MC ch
|
||||
&pshufb ("xmm1","xmm3"); # 0 = sbdt
|
||||
&pxor ("xmm0","xmm4"); # 4 = ch
|
||||
&movdqa ("xmm4",&QWP(0x20,$base)); # 4 : sbbu
|
||||
&pxor ("xmm0","xmm1"); # 0 = ch
|
||||
&movdqa ("xmm1",&QWP(0x30,$base)); # 0 : sbbt
|
||||
|
||||
&pshufb ("xmm4","xmm2"); # 4 = sbbu
|
||||
&pshufb ("xmm0","xmm5"); # MC ch
|
||||
&pshufb ("xmm1","xmm3"); # 0 = sbbt
|
||||
&pxor ("xmm0","xmm4"); # 4 = ch
|
||||
&movdqa ("xmm4",&QWP(0x40,$base)); # 4 : sbeu
|
||||
&pxor ("xmm0","xmm1"); # 0 = ch
|
||||
&movdqa ("xmm1",&QWP(0x50,$base)); # 0 : sbet
|
||||
|
||||
&pshufb ("xmm4","xmm2"); # 4 = sbeu
|
||||
&pshufb ("xmm0","xmm5"); # MC ch
|
||||
&pshufb ("xmm1","xmm3"); # 0 = sbet
|
||||
&pxor ("xmm0","xmm4"); # 4 = ch
|
||||
&add ($key,16); # next round key
|
||||
&palignr("xmm5","xmm5",12);
|
||||
&pxor ("xmm0","xmm1"); # 0 = ch
|
||||
&sub ($round,1); # nr--
|
||||
|
||||
&set_label("dec_entry");
|
||||
# top of round
|
||||
&movdqa ("xmm1","xmm6"); # 1 : i
|
||||
&movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k
|
||||
&pandn ("xmm1","xmm0"); # 1 = i<<4
|
||||
&pand ("xmm0","xmm6"); # 0 = k
|
||||
&psrld ("xmm1",4); # 1 = i
|
||||
&pshufb ("xmm2","xmm0"); # 2 = a/k
|
||||
&movdqa ("xmm3","xmm7"); # 3 : 1/i
|
||||
&pxor ("xmm0","xmm1"); # 0 = j
|
||||
&pshufb ("xmm3","xmm1"); # 3 = 1/i
|
||||
&movdqa ("xmm4","xmm7"); # 4 : 1/j
|
||||
&pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k
|
||||
&pshufb ("xmm4","xmm0"); # 4 = 1/j
|
||||
&pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k
|
||||
&movdqa ("xmm2","xmm7"); # 2 : 1/iak
|
||||
&pshufb ("xmm2","xmm3"); # 2 = 1/iak
|
||||
&movdqa ("xmm3","xmm7"); # 3 : 1/jak
|
||||
&pxor ("xmm2","xmm0"); # 2 = io
|
||||
&pshufb ("xmm3","xmm4"); # 3 = 1/jak
|
||||
&movdqu ("xmm0",&QWP(0,$key));
|
||||
&pxor ("xmm3","xmm1"); # 3 = jo
|
||||
&jnz (&label("dec_loop"));
|
||||
|
||||
# middle of last round
|
||||
&movdqa ("xmm4",&QWP(0x60,$base)); # 3 : sbou
|
||||
&pshufb ("xmm4","xmm2"); # 4 = sbou
|
||||
&pxor ("xmm4","xmm0"); # 4 = sb1u + k
|
||||
&movdqa ("xmm0",&QWP(0x70,$base)); # 0 : sbot
|
||||
&movdqa ("xmm2",&QWP(0,$magic));
|
||||
&pshufb ("xmm0","xmm3"); # 0 = sb1t
|
||||
&pxor ("xmm0","xmm4"); # 0 = A
|
||||
&pshufb ("xmm0","xmm2");
|
||||
&ret ();
|
||||
&function_end_B("_vpaes_decrypt_core");
|
||||
|
||||
########################################################
|
||||
## ##
|
||||
## AES key schedule ##
|
||||
## ##
|
||||
########################################################
|
||||
&function_begin_B("_vpaes_schedule_core");
|
||||
&add ($const,&DWP(0,"esp"));
|
||||
&movdqu ("xmm0",&QWP(0,$inp)); # load key (unaligned)
|
||||
&movdqa ("xmm2",&QWP($k_rcon,$const)); # load rcon
|
||||
|
||||
# input transform
|
||||
&movdqa ("xmm3","xmm0");
|
||||
&lea ($base,&DWP($k_ipt,$const));
|
||||
&movdqa (&QWP(4,"esp"),"xmm2"); # xmm8
|
||||
&call ("_vpaes_schedule_transform");
|
||||
&movdqa ("xmm7","xmm0");
|
||||
|
||||
&test ($out,$out);
|
||||
&jnz (&label("schedule_am_decrypting"));
|
||||
|
||||
# encrypting, output zeroth round key after transform
|
||||
&movdqu (&QWP(0,$key),"xmm0");
|
||||
&jmp (&label("schedule_go"));
|
||||
|
||||
&set_label("schedule_am_decrypting");
|
||||
# decrypting, output zeroth round key after shiftrows
|
||||
&movdqa ("xmm1",&QWP($k_sr,$const,$magic));
|
||||
&pshufb ("xmm3","xmm1");
|
||||
&movdqu (&QWP(0,$key),"xmm3");
|
||||
&xor ($magic,0x30);
|
||||
|
||||
&set_label("schedule_go");
|
||||
&cmp ($round,192);
|
||||
&ja (&label("schedule_256"));
|
||||
&je (&label("schedule_192"));
|
||||
# 128: fall though
|
||||
|
||||
##
|
||||
## .schedule_128
|
||||
##
|
||||
## 128-bit specific part of key schedule.
|
||||
##
|
||||
## This schedule is really simple, because all its parts
|
||||
## are accomplished by the subroutines.
|
||||
##
|
||||
&set_label("schedule_128");
|
||||
&mov ($round,10);
|
||||
|
||||
&set_label("loop_schedule_128");
|
||||
&call ("_vpaes_schedule_round");
|
||||
&dec ($round);
|
||||
&jz (&label("schedule_mangle_last"));
|
||||
&call ("_vpaes_schedule_mangle"); # write output
|
||||
&jmp (&label("loop_schedule_128"));
|
||||
|
||||
##
|
||||
## .aes_schedule_192
|
||||
##
|
||||
## 192-bit specific part of key schedule.
|
||||
##
|
||||
## The main body of this schedule is the same as the 128-bit
|
||||
## schedule, but with more smearing. The long, high side is
|
||||
## stored in %xmm7 as before, and the short, low side is in
|
||||
## the high bits of %xmm6.
|
||||
##
|
||||
## This schedule is somewhat nastier, however, because each
|
||||
## round produces 192 bits of key material, or 1.5 round keys.
|
||||
## Therefore, on each cycle we do 2 rounds and produce 3 round
|
||||
## keys.
|
||||
##
|
||||
&set_label("schedule_192",16);
|
||||
&movdqu ("xmm0",&QWP(8,$inp)); # load key part 2 (very unaligned)
|
||||
&call ("_vpaes_schedule_transform"); # input transform
|
||||
&movdqa ("xmm6","xmm0"); # save short part
|
||||
&pxor ("xmm4","xmm4"); # clear 4
|
||||
&movhlps("xmm6","xmm4"); # clobber low side with zeros
|
||||
&mov ($round,4);
|
||||
|
||||
&set_label("loop_schedule_192");
|
||||
&call ("_vpaes_schedule_round");
|
||||
&palignr("xmm0","xmm6",8);
|
||||
&call ("_vpaes_schedule_mangle"); # save key n
|
||||
&call ("_vpaes_schedule_192_smear");
|
||||
&call ("_vpaes_schedule_mangle"); # save key n+1
|
||||
&call ("_vpaes_schedule_round");
|
||||
&dec ($round);
|
||||
&jz (&label("schedule_mangle_last"));
|
||||
&call ("_vpaes_schedule_mangle"); # save key n+2
|
||||
&call ("_vpaes_schedule_192_smear");
|
||||
&jmp (&label("loop_schedule_192"));
|
||||
|
||||
##
|
||||
## .aes_schedule_256
|
||||
##
|
||||
## 256-bit specific part of key schedule.
|
||||
##
|
||||
## The structure here is very similar to the 128-bit
|
||||
## schedule, but with an additional "low side" in
|
||||
## %xmm6. The low side's rounds are the same as the
|
||||
## high side's, except no rcon and no rotation.
|
||||
##
|
||||
&set_label("schedule_256",16);
|
||||
&movdqu ("xmm0",&QWP(16,$inp)); # load key part 2 (unaligned)
|
||||
&call ("_vpaes_schedule_transform"); # input transform
|
||||
&mov ($round,7);
|
||||
|
||||
&set_label("loop_schedule_256");
|
||||
&call ("_vpaes_schedule_mangle"); # output low result
|
||||
&movdqa ("xmm6","xmm0"); # save cur_lo in xmm6
|
||||
|
||||
# high round
|
||||
&call ("_vpaes_schedule_round");
|
||||
&dec ($round);
|
||||
&jz (&label("schedule_mangle_last"));
|
||||
&call ("_vpaes_schedule_mangle");
|
||||
|
||||
# low round. swap xmm7 and xmm6
|
||||
&pshufd ("xmm0","xmm0",0xFF);
|
||||
&movdqa (&QWP(20,"esp"),"xmm7");
|
||||
&movdqa ("xmm7","xmm6");
|
||||
&call ("_vpaes_schedule_low_round");
|
||||
&movdqa ("xmm7",&QWP(20,"esp"));
|
||||
|
||||
&jmp (&label("loop_schedule_256"));
|
||||
|
||||
##
|
||||
## .aes_schedule_mangle_last
|
||||
##
|
||||
## Mangler for last round of key schedule
|
||||
## Mangles %xmm0
|
||||
## when encrypting, outputs out(%xmm0) ^ 63
|
||||
## when decrypting, outputs unskew(%xmm0)
|
||||
##
|
||||
## Always called right before return... jumps to cleanup and exits
|
||||
##
|
||||
&set_label("schedule_mangle_last",16);
|
||||
# schedule last round key from xmm0
|
||||
&lea ($base,&DWP($k_deskew,$const));
|
||||
&test ($out,$out);
|
||||
&jnz (&label("schedule_mangle_last_dec"));
|
||||
|
||||
# encrypting
|
||||
&movdqa ("xmm1",&QWP($k_sr,$const,$magic));
|
||||
&pshufb ("xmm0","xmm1"); # output permute
|
||||
&lea ($base,&DWP($k_opt,$const)); # prepare to output transform
|
||||
&add ($key,32);
|
||||
|
||||
&set_label("schedule_mangle_last_dec");
|
||||
&add ($key,-16);
|
||||
&pxor ("xmm0",&QWP($k_s63,$const));
|
||||
&call ("_vpaes_schedule_transform"); # output transform
|
||||
&movdqu (&QWP(0,$key),"xmm0"); # save last key
|
||||
|
||||
# cleanup
|
||||
&pxor ("xmm0","xmm0");
|
||||
&pxor ("xmm1","xmm1");
|
||||
&pxor ("xmm2","xmm2");
|
||||
&pxor ("xmm3","xmm3");
|
||||
&pxor ("xmm4","xmm4");
|
||||
&pxor ("xmm5","xmm5");
|
||||
&pxor ("xmm6","xmm6");
|
||||
&pxor ("xmm7","xmm7");
|
||||
&ret ();
|
||||
&function_end_B("_vpaes_schedule_core");
|
||||
|
||||
##
|
||||
## .aes_schedule_192_smear
|
||||
##
|
||||
## Smear the short, low side in the 192-bit key schedule.
|
||||
##
|
||||
## Inputs:
|
||||
## %xmm7: high side, b a x y
|
||||
## %xmm6: low side, d c 0 0
|
||||
## %xmm13: 0
|
||||
##
|
||||
## Outputs:
|
||||
## %xmm6: b+c+d b+c 0 0
|
||||
## %xmm0: b+c+d b+c b a
|
||||
##
|
||||
&function_begin_B("_vpaes_schedule_192_smear");
|
||||
&pshufd ("xmm1","xmm6",0x80); # d c 0 0 -> c 0 0 0
|
||||
&pshufd ("xmm0","xmm7",0xFE); # b a _ _ -> b b b a
|
||||
&pxor ("xmm6","xmm1"); # -> c+d c 0 0
|
||||
&pxor ("xmm1","xmm1");
|
||||
&pxor ("xmm6","xmm0"); # -> b+c+d b+c b a
|
||||
&movdqa ("xmm0","xmm6");
|
||||
&movhlps("xmm6","xmm1"); # clobber low side with zeros
|
||||
&ret ();
|
||||
&function_end_B("_vpaes_schedule_192_smear");
|
||||
|
||||
##
|
||||
## .aes_schedule_round
|
||||
##
|
||||
## Runs one main round of the key schedule on %xmm0, %xmm7
|
||||
##
|
||||
## Specifically, runs subbytes on the high dword of %xmm0
|
||||
## then rotates it by one byte and xors into the low dword of
|
||||
## %xmm7.
|
||||
##
|
||||
## Adds rcon from low byte of %xmm8, then rotates %xmm8 for
|
||||
## next rcon.
|
||||
##
|
||||
## Smears the dwords of %xmm7 by xoring the low into the
|
||||
## second low, result into third, result into highest.
|
||||
##
|
||||
## Returns results in %xmm7 = %xmm0.
|
||||
## Clobbers %xmm1-%xmm5.
|
||||
##
|
||||
&function_begin_B("_vpaes_schedule_round");
|
||||
# extract rcon from xmm8
|
||||
&movdqa ("xmm2",&QWP(8,"esp")); # xmm8
|
||||
&pxor ("xmm1","xmm1");
|
||||
&palignr("xmm1","xmm2",15);
|
||||
&palignr("xmm2","xmm2",15);
|
||||
&pxor ("xmm7","xmm1");
|
||||
|
||||
# rotate
|
||||
&pshufd ("xmm0","xmm0",0xFF);
|
||||
&palignr("xmm0","xmm0",1);
|
||||
|
||||
# fall through...
|
||||
&movdqa (&QWP(8,"esp"),"xmm2"); # xmm8
|
||||
|
||||
# low round: same as high round, but no rotation and no rcon.
|
||||
&set_label("_vpaes_schedule_low_round");
|
||||
# smear xmm7
|
||||
&movdqa ("xmm1","xmm7");
|
||||
&pslldq ("xmm7",4);
|
||||
&pxor ("xmm7","xmm1");
|
||||
&movdqa ("xmm1","xmm7");
|
||||
&pslldq ("xmm7",8);
|
||||
&pxor ("xmm7","xmm1");
|
||||
&pxor ("xmm7",&QWP($k_s63,$const));
|
||||
|
||||
# subbyte
|
||||
&movdqa ("xmm4",&QWP($k_s0F,$const));
|
||||
&movdqa ("xmm5",&QWP($k_inv,$const)); # 4 : 1/j
|
||||
&movdqa ("xmm1","xmm4");
|
||||
&pandn ("xmm1","xmm0");
|
||||
&psrld ("xmm1",4); # 1 = i
|
||||
&pand ("xmm0","xmm4"); # 0 = k
|
||||
&movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k
|
||||
&pshufb ("xmm2","xmm0"); # 2 = a/k
|
||||
&pxor ("xmm0","xmm1"); # 0 = j
|
||||
&movdqa ("xmm3","xmm5"); # 3 : 1/i
|
||||
&pshufb ("xmm3","xmm1"); # 3 = 1/i
|
||||
&pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k
|
||||
&movdqa ("xmm4","xmm5"); # 4 : 1/j
|
||||
&pshufb ("xmm4","xmm0"); # 4 = 1/j
|
||||
&pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k
|
||||
&movdqa ("xmm2","xmm5"); # 2 : 1/iak
|
||||
&pshufb ("xmm2","xmm3"); # 2 = 1/iak
|
||||
&pxor ("xmm2","xmm0"); # 2 = io
|
||||
&movdqa ("xmm3","xmm5"); # 3 : 1/jak
|
||||
&pshufb ("xmm3","xmm4"); # 3 = 1/jak
|
||||
&pxor ("xmm3","xmm1"); # 3 = jo
|
||||
&movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sbou
|
||||
&pshufb ("xmm4","xmm2"); # 4 = sbou
|
||||
&movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sbot
|
||||
&pshufb ("xmm0","xmm3"); # 0 = sb1t
|
||||
&pxor ("xmm0","xmm4"); # 0 = sbox output
|
||||
|
||||
# add in smeared stuff
|
||||
&pxor ("xmm0","xmm7");
|
||||
&movdqa ("xmm7","xmm0");
|
||||
&ret ();
|
||||
&function_end_B("_vpaes_schedule_round");
|
||||
|
||||
##
|
||||
## .aes_schedule_transform
|
||||
##
|
||||
## Linear-transform %xmm0 according to tables at (%ebx)
|
||||
##
|
||||
## Output in %xmm0
|
||||
## Clobbers %xmm1, %xmm2
|
||||
##
|
||||
&function_begin_B("_vpaes_schedule_transform");
|
||||
&movdqa ("xmm2",&QWP($k_s0F,$const));
|
||||
&movdqa ("xmm1","xmm2");
|
||||
&pandn ("xmm1","xmm0");
|
||||
&psrld ("xmm1",4);
|
||||
&pand ("xmm0","xmm2");
|
||||
&movdqa ("xmm2",&QWP(0,$base));
|
||||
&pshufb ("xmm2","xmm0");
|
||||
&movdqa ("xmm0",&QWP(16,$base));
|
||||
&pshufb ("xmm0","xmm1");
|
||||
&pxor ("xmm0","xmm2");
|
||||
&ret ();
|
||||
&function_end_B("_vpaes_schedule_transform");
|
||||
|
||||
##
|
||||
## .aes_schedule_mangle
|
||||
##
|
||||
## Mangle xmm0 from (basis-transformed) standard version
|
||||
## to our version.
|
||||
##
|
||||
## On encrypt,
|
||||
## xor with 0x63
|
||||
## multiply by circulant 0,1,1,1
|
||||
## apply shiftrows transform
|
||||
##
|
||||
## On decrypt,
|
||||
## xor with 0x63
|
||||
## multiply by "inverse mixcolumns" circulant E,B,D,9
|
||||
## deskew
|
||||
## apply shiftrows transform
|
||||
##
|
||||
##
|
||||
## Writes out to (%edx), and increments or decrements it
|
||||
## Keeps track of round number mod 4 in %ecx
|
||||
## Preserves xmm0
|
||||
## Clobbers xmm1-xmm5
|
||||
##
|
||||
&function_begin_B("_vpaes_schedule_mangle");
|
||||
&movdqa ("xmm4","xmm0"); # save xmm0 for later
|
||||
&movdqa ("xmm5",&QWP($k_mc_forward,$const));
|
||||
&test ($out,$out);
|
||||
&jnz (&label("schedule_mangle_dec"));
|
||||
|
||||
# encrypting
|
||||
&add ($key,16);
|
||||
&pxor ("xmm4",&QWP($k_s63,$const));
|
||||
&pshufb ("xmm4","xmm5");
|
||||
&movdqa ("xmm3","xmm4");
|
||||
&pshufb ("xmm4","xmm5");
|
||||
&pxor ("xmm3","xmm4");
|
||||
&pshufb ("xmm4","xmm5");
|
||||
&pxor ("xmm3","xmm4");
|
||||
|
||||
&jmp (&label("schedule_mangle_both"));
|
||||
|
||||
&set_label("schedule_mangle_dec",16);
|
||||
# inverse mix columns
|
||||
&movdqa ("xmm2",&QWP($k_s0F,$const));
|
||||
&lea ($inp,&DWP($k_dksd,$const));
|
||||
&movdqa ("xmm1","xmm2");
|
||||
&pandn ("xmm1","xmm4");
|
||||
&psrld ("xmm1",4); # 1 = hi
|
||||
&pand ("xmm4","xmm2"); # 4 = lo
|
||||
|
||||
&movdqa ("xmm2",&QWP(0,$inp));
|
||||
&pshufb ("xmm2","xmm4");
|
||||
&movdqa ("xmm3",&QWP(0x10,$inp));
|
||||
&pshufb ("xmm3","xmm1");
|
||||
&pxor ("xmm3","xmm2");
|
||||
&pshufb ("xmm3","xmm5");
|
||||
|
||||
&movdqa ("xmm2",&QWP(0x20,$inp));
|
||||
&pshufb ("xmm2","xmm4");
|
||||
&pxor ("xmm2","xmm3");
|
||||
&movdqa ("xmm3",&QWP(0x30,$inp));
|
||||
&pshufb ("xmm3","xmm1");
|
||||
&pxor ("xmm3","xmm2");
|
||||
&pshufb ("xmm3","xmm5");
|
||||
|
||||
&movdqa ("xmm2",&QWP(0x40,$inp));
|
||||
&pshufb ("xmm2","xmm4");
|
||||
&pxor ("xmm2","xmm3");
|
||||
&movdqa ("xmm3",&QWP(0x50,$inp));
|
||||
&pshufb ("xmm3","xmm1");
|
||||
&pxor ("xmm3","xmm2");
|
||||
&pshufb ("xmm3","xmm5");
|
||||
|
||||
&movdqa ("xmm2",&QWP(0x60,$inp));
|
||||
&pshufb ("xmm2","xmm4");
|
||||
&pxor ("xmm2","xmm3");
|
||||
&movdqa ("xmm3",&QWP(0x70,$inp));
|
||||
&pshufb ("xmm3","xmm1");
|
||||
&pxor ("xmm3","xmm2");
|
||||
|
||||
&add ($key,-16);
|
||||
|
||||
&set_label("schedule_mangle_both");
|
||||
&movdqa ("xmm1",&QWP($k_sr,$const,$magic));
|
||||
&pshufb ("xmm3","xmm1");
|
||||
&add ($magic,-16);
|
||||
&and ($magic,0x30);
|
||||
&movdqu (&QWP(0,$key),"xmm3");
|
||||
&ret ();
|
||||
&function_end_B("_vpaes_schedule_mangle");
|
||||
|
||||
#
|
||||
# Interface to OpenSSL
|
||||
#
|
||||
&function_begin("${PREFIX}_set_encrypt_key");
|
||||
&mov ($inp,&wparam(0)); # inp
|
||||
&lea ($base,&DWP(-56,"esp"));
|
||||
&mov ($round,&wparam(1)); # bits
|
||||
&and ($base,-16);
|
||||
&mov ($key,&wparam(2)); # key
|
||||
&xchg ($base,"esp"); # alloca
|
||||
&mov (&DWP(48,"esp"),$base);
|
||||
|
||||
&mov ($base,$round);
|
||||
&shr ($base,5);
|
||||
&add ($base,5);
|
||||
&mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5;
|
||||
&mov ($magic,0x30);
|
||||
&mov ($out,0);
|
||||
|
||||
&lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
|
||||
&call ("_vpaes_schedule_core");
|
||||
&set_label("pic_point");
|
||||
|
||||
&mov ("esp",&DWP(48,"esp"));
|
||||
&xor ("eax","eax");
|
||||
&function_end("${PREFIX}_set_encrypt_key");
|
||||
|
||||
&function_begin("${PREFIX}_set_decrypt_key");
|
||||
&mov ($inp,&wparam(0)); # inp
|
||||
&lea ($base,&DWP(-56,"esp"));
|
||||
&mov ($round,&wparam(1)); # bits
|
||||
&and ($base,-16);
|
||||
&mov ($key,&wparam(2)); # key
|
||||
&xchg ($base,"esp"); # alloca
|
||||
&mov (&DWP(48,"esp"),$base);
|
||||
|
||||
&mov ($base,$round);
|
||||
&shr ($base,5);
|
||||
&add ($base,5);
|
||||
&mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5;
|
||||
&shl ($base,4);
|
||||
&lea ($key,&DWP(16,$key,$base));
|
||||
|
||||
&mov ($out,1);
|
||||
&mov ($magic,$round);
|
||||
&shr ($magic,1);
|
||||
&and ($magic,32);
|
||||
&xor ($magic,32); # nbist==192?0:32;
|
||||
|
||||
&lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
|
||||
&call ("_vpaes_schedule_core");
|
||||
&set_label("pic_point");
|
||||
|
||||
&mov ("esp",&DWP(48,"esp"));
|
||||
&xor ("eax","eax");
|
||||
&function_end("${PREFIX}_set_decrypt_key");
|
||||
|
||||
&function_begin("${PREFIX}_encrypt");
|
||||
&lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
|
||||
&call ("_vpaes_preheat");
|
||||
&set_label("pic_point");
|
||||
&mov ($inp,&wparam(0)); # inp
|
||||
&lea ($base,&DWP(-56,"esp"));
|
||||
&mov ($out,&wparam(1)); # out
|
||||
&and ($base,-16);
|
||||
&mov ($key,&wparam(2)); # key
|
||||
&xchg ($base,"esp"); # alloca
|
||||
&mov (&DWP(48,"esp"),$base);
|
||||
|
||||
&movdqu ("xmm0",&QWP(0,$inp));
|
||||
&call ("_vpaes_encrypt_core");
|
||||
&movdqu (&QWP(0,$out),"xmm0");
|
||||
|
||||
&mov ("esp",&DWP(48,"esp"));
|
||||
&function_end("${PREFIX}_encrypt");
|
||||
|
||||
&function_begin("${PREFIX}_decrypt");
|
||||
&lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
|
||||
&call ("_vpaes_preheat");
|
||||
&set_label("pic_point");
|
||||
&mov ($inp,&wparam(0)); # inp
|
||||
&lea ($base,&DWP(-56,"esp"));
|
||||
&mov ($out,&wparam(1)); # out
|
||||
&and ($base,-16);
|
||||
&mov ($key,&wparam(2)); # key
|
||||
&xchg ($base,"esp"); # alloca
|
||||
&mov (&DWP(48,"esp"),$base);
|
||||
|
||||
&movdqu ("xmm0",&QWP(0,$inp));
|
||||
&call ("_vpaes_decrypt_core");
|
||||
&movdqu (&QWP(0,$out),"xmm0");
|
||||
|
||||
&mov ("esp",&DWP(48,"esp"));
|
||||
&function_end("${PREFIX}_decrypt");
|
||||
|
||||
&function_begin("${PREFIX}_cbc_encrypt");
|
||||
&mov ($inp,&wparam(0)); # inp
|
||||
&mov ($out,&wparam(1)); # out
|
||||
&mov ($round,&wparam(2)); # len
|
||||
&mov ($key,&wparam(3)); # key
|
||||
&sub ($round,16);
|
||||
&jc (&label("cbc_abort"));
|
||||
&lea ($base,&DWP(-56,"esp"));
|
||||
&mov ($const,&wparam(4)); # ivp
|
||||
&and ($base,-16);
|
||||
&mov ($magic,&wparam(5)); # enc
|
||||
&xchg ($base,"esp"); # alloca
|
||||
&movdqu ("xmm1",&QWP(0,$const)); # load IV
|
||||
&sub ($out,$inp);
|
||||
&mov (&DWP(48,"esp"),$base);
|
||||
|
||||
&mov (&DWP(0,"esp"),$out); # save out
|
||||
&mov (&DWP(4,"esp"),$key) # save key
|
||||
&mov (&DWP(8,"esp"),$const); # save ivp
|
||||
&mov ($out,$round); # $out works as $len
|
||||
|
||||
&lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point")));
|
||||
&call ("_vpaes_preheat");
|
||||
&set_label("pic_point");
|
||||
&cmp ($magic,0);
|
||||
&je (&label("cbc_dec_loop"));
|
||||
&jmp (&label("cbc_enc_loop"));
|
||||
|
||||
&set_label("cbc_enc_loop",16);
|
||||
&movdqu ("xmm0",&QWP(0,$inp)); # load input
|
||||
&pxor ("xmm0","xmm1"); # inp^=iv
|
||||
&call ("_vpaes_encrypt_core");
|
||||
&mov ($base,&DWP(0,"esp")); # restore out
|
||||
&mov ($key,&DWP(4,"esp")); # restore key
|
||||
&movdqa ("xmm1","xmm0");
|
||||
&movdqu (&QWP(0,$base,$inp),"xmm0"); # write output
|
||||
&lea ($inp,&DWP(16,$inp));
|
||||
&sub ($out,16);
|
||||
&jnc (&label("cbc_enc_loop"));
|
||||
&jmp (&label("cbc_done"));
|
||||
|
||||
&set_label("cbc_dec_loop",16);
|
||||
&movdqu ("xmm0",&QWP(0,$inp)); # load input
|
||||
&movdqa (&QWP(16,"esp"),"xmm1"); # save IV
|
||||
&movdqa (&QWP(32,"esp"),"xmm0"); # save future IV
|
||||
&call ("_vpaes_decrypt_core");
|
||||
&mov ($base,&DWP(0,"esp")); # restore out
|
||||
&mov ($key,&DWP(4,"esp")); # restore key
|
||||
&pxor ("xmm0",&QWP(16,"esp")); # out^=iv
|
||||
&movdqa ("xmm1",&QWP(32,"esp")); # load next IV
|
||||
&movdqu (&QWP(0,$base,$inp),"xmm0"); # write output
|
||||
&lea ($inp,&DWP(16,$inp));
|
||||
&sub ($out,16);
|
||||
&jnc (&label("cbc_dec_loop"));
|
||||
|
||||
&set_label("cbc_done");
|
||||
&mov ($base,&DWP(8,"esp")); # restore ivp
|
||||
&mov ("esp",&DWP(48,"esp"));
|
||||
&movdqu (&QWP(0,$base),"xmm1"); # write IV
|
||||
&set_label("cbc_abort");
|
||||
&function_end("${PREFIX}_cbc_encrypt");
|
||||
|
||||
&asm_finish();
|
||||
|
||||
close STDOUT or die "error closing STDOUT: $!";
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,154 @@
|
||||
LIBS=../../libcrypto
|
||||
|
||||
$AESASM=aes_core.c aes_cbc.c
|
||||
IF[{- !$disabled{asm} -}]
|
||||
$AESASM_x86=aes-586.S
|
||||
$AESDEF_x86=AES_ASM
|
||||
$AESASM_x86_sse2=vpaes-x86.S aesni-x86.S
|
||||
$AESDEF_x86_sse2=VPAES_ASM OPENSSL_IA32_SSE2
|
||||
|
||||
$AESASM_x86_64=\
|
||||
aes-x86_64.s vpaes-x86_64.s bsaes-x86_64.s aesni-x86_64.s \
|
||||
aesni-sha1-x86_64.s aesni-sha256-x86_64.s aesni-mb-x86_64.s \
|
||||
aesni-xts-avx512.s
|
||||
$AESDEF_x86_64=AES_ASM VPAES_ASM BSAES_ASM
|
||||
|
||||
$AESASM_ia64=aes_core.c aes_cbc.c aes-ia64.s
|
||||
$AESDEF_ia64=AES_ASM
|
||||
|
||||
$AESASM_sparcv9=\
|
||||
aes_core.c aes_cbc.c aes-sparcv9.S aest4-sparcv9.S aesfx-sparcv9.S
|
||||
$AESDEF_sparcv9=AES_ASM
|
||||
|
||||
$AESASM_mips32=aes_cbc.c aes-mips.S
|
||||
$AESDEF_mips32=AES_ASM
|
||||
$AESASM_mips64=$AESASM_mips32
|
||||
$AESDEF_mips64=$AESDEF_mips32
|
||||
|
||||
$AESASM_s390x=aes-s390x.S
|
||||
# aes-390x.S implements AES_ctr32_encrypt and AES_xts_[en|de]crypt
|
||||
$AESDEF_s390x=AES_ASM AES_CTR_ASM AES_XTS_ASM
|
||||
|
||||
$AESASM_armv4=aes_cbc.c aes-armv4.S bsaes-armv7.S aesv8-armx.S
|
||||
$AESDEF_armv4=AES_ASM BSAES_ASM
|
||||
$AESASM_aarch64=aes_core.c aes_cbc.c aesv8-armx.S bsaes-armv8.S vpaes-armv8.S
|
||||
$AESDEF_aarch64=BSAES_ASM VPAES_ASM
|
||||
|
||||
$AESASM_parisc11=aes_core.c aes_cbc.c aes-parisc.s
|
||||
$AESDEF_parisc11=AES_ASM
|
||||
$AESASM_parisc20_64=$AESASM_parisc11
|
||||
$AESDEF_parisc20_64=$AESDEF_parisc11
|
||||
|
||||
IF[{- $target{sys_id} ne "MACOSX" -}]
|
||||
$AESASM_ppc32=aes_core.c aes_cbc.c aes-ppc.s vpaes-ppc.s aesp8-ppc.s
|
||||
ELSE
|
||||
$AESASM_ppc32=aes_core.c aes_cbc.c aes-ppc.s vpaes-ppc.s
|
||||
ENDIF
|
||||
$AESDEF_ppc32=AES_ASM VPAES_ASM
|
||||
$AESASM_ppc64=$AESASM_ppc32
|
||||
$AESDEF_ppc64=$AESDEF_ppc32
|
||||
|
||||
$AESASM_c64xplus=aes-c64xplus.s aes_cbc.c
|
||||
# aes-c64xplus.s implements AES_ctr32_encrypt
|
||||
$AESDEF_c64xplus=AES_ASM AES_CTR_ASM
|
||||
|
||||
$AESASM_riscv64=aes_cbc.c aes-riscv64.s aes-riscv64-zkn.s aes-riscv64-zvkb-zvkned.s aes-riscv64-zvkned.s aes-riscv64-zvbb-zvkg-zvkned.s
|
||||
$AESDEF_riscv64=AES_ASM
|
||||
$AESASM_riscv32=aes_core.c aes_cbc.c aes-riscv32-zkn.s
|
||||
|
||||
$AESASM_loongarch64=aes_core.c aes_cbc.c vpaes-loongarch64.S
|
||||
$AESDEF_loongarch64=VPAES_ASM
|
||||
|
||||
# Now that we have defined all the arch specific variables, use the
|
||||
# appropriate one, and define the appropriate macros
|
||||
IF[$AESASM_{- $target{asm_arch} -}]
|
||||
$AESASM=$AESASM_{- $target{asm_arch} -}
|
||||
$AESDEF=$AESDEF_{- $target{asm_arch} -}
|
||||
IF[{- !$disabled{sse2} -}]
|
||||
$AESASM=$AESASM $AESASM_{- $target{asm_arch} -}_sse2
|
||||
$AESDEF=$AESDEF $AESDEF_{- $target{asm_arch} -}_sse2
|
||||
ENDIF
|
||||
ENDIF
|
||||
ENDIF
|
||||
|
||||
$COMMON=aes_misc.c aes_ecb.c $AESASM
|
||||
SOURCE[../../libcrypto]=$COMMON aes_cfb.c aes_ofb.c aes_wrap.c
|
||||
IF[{- !$disabled{'deprecated-3.0'} -}]
|
||||
SOURCE[../../libcrypto]=aes_ige.c
|
||||
ENDIF
|
||||
SOURCE[../../providers/libfips.a]=$COMMON
|
||||
|
||||
# Implementations are now spread across several libraries, so the defines
|
||||
# need to be applied to all affected libraries and modules.
|
||||
DEFINE[../../libcrypto]=$AESDEF
|
||||
DEFINE[../../providers/libfips.a]=$AESDEF
|
||||
DEFINE[../../providers/libdefault.a]=$AESDEF
|
||||
# We only need to include the AESDEF stuff in the legacy provider when it's a
|
||||
# separate module and it's dynamically linked with libcrypto. Otherwise, it
|
||||
# already gets everything that the static libcrypto.a has, and doesn't need it
|
||||
# added again.
|
||||
IF[{- !$disabled{module} && !$disabled{shared} -}]
|
||||
DEFINE[../../providers/liblegacy.a]=$AESDEF
|
||||
ENDIF
|
||||
|
||||
GENERATE[aes-ia64.s]=asm/aes-ia64.S
|
||||
GENERATE[bsaes-armv8.S]=asm/bsaes-armv8.pl
|
||||
|
||||
GENERATE[aes-586.S]=asm/aes-586.pl
|
||||
DEPEND[aes-586.S]=../perlasm/x86asm.pl
|
||||
GENERATE[vpaes-x86.S]=asm/vpaes-x86.pl
|
||||
DEPEND[vpaes-586.S]=../perlasm/x86asm.pl
|
||||
GENERATE[aesni-x86.S]=asm/aesni-x86.pl
|
||||
DEPEND[aesni-586.S]=../perlasm/x86asm.pl
|
||||
|
||||
GENERATE[aes-x86_64.s]=asm/aes-x86_64.pl
|
||||
GENERATE[vpaes-x86_64.s]=asm/vpaes-x86_64.pl
|
||||
GENERATE[bsaes-x86_64.s]=asm/bsaes-x86_64.pl
|
||||
GENERATE[aesni-x86_64.s]=asm/aesni-x86_64.pl
|
||||
GENERATE[aesni-sha1-x86_64.s]=asm/aesni-sha1-x86_64.pl
|
||||
GENERATE[aesni-sha256-x86_64.s]=asm/aesni-sha256-x86_64.pl
|
||||
GENERATE[aesni-mb-x86_64.s]=asm/aesni-mb-x86_64.pl
|
||||
|
||||
GENERATE[aes-sparcv9.S]=asm/aes-sparcv9.pl
|
||||
INCLUDE[aes-sparcv9.o]=..
|
||||
GENERATE[aest4-sparcv9.S]=asm/aest4-sparcv9.pl
|
||||
INCLUDE[aest4-sparcv9.o]=..
|
||||
DEPEND[aest4-sparcv9.S]=../perlasm/sparcv9_modes.pl
|
||||
GENERATE[aesfx-sparcv9.S]=asm/aesfx-sparcv9.pl
|
||||
INCLUDE[aesfx-sparcv9.o]=..
|
||||
|
||||
GENERATE[aes-ppc.s]=asm/aes-ppc.pl
|
||||
GENERATE[vpaes-ppc.s]=asm/vpaes-ppc.pl
|
||||
GENERATE[aesp8-ppc.s]=asm/aesp8-ppc.pl
|
||||
|
||||
GENERATE[aes-parisc.s]=asm/aes-parisc.pl
|
||||
|
||||
GENERATE[aes-mips.S]=asm/aes-mips.pl
|
||||
INCLUDE[aes-mips.o]=..
|
||||
|
||||
GENERATE[aes-riscv64.s]=asm/aes-riscv64.pl
|
||||
GENERATE[aes-riscv64-zkn.s]=asm/aes-riscv64-zkn.pl
|
||||
GENERATE[aes-riscv32-zkn.s]=asm/aes-riscv32-zkn.pl
|
||||
GENERATE[aes-riscv64-zvkb-zvkned.s]=asm/aes-riscv64-zvkb-zvkned.pl
|
||||
GENERATE[aes-riscv64-zvkned.s]=asm/aes-riscv64-zvkned.pl
|
||||
GENERATE[aes-riscv64-zvbb-zvkg-zvkned.s]=asm/aes-riscv64-zvbb-zvkg-zvkned.pl
|
||||
|
||||
GENERATE[aesv8-armx.S]=asm/aesv8-armx.pl
|
||||
INCLUDE[aesv8-armx.o]=..
|
||||
GENERATE[vpaes-armv8.S]=asm/vpaes-armv8.pl
|
||||
INCLUDE[vpaes-armv8.o]=..
|
||||
|
||||
GENERATE[aes-armv4.S]=asm/aes-armv4.pl
|
||||
INCLUDE[aes-armv4.o]=..
|
||||
GENERATE[bsaes-armv7.S]=asm/bsaes-armv7.pl
|
||||
INCLUDE[bsaes-armv7.o]=..
|
||||
|
||||
GENERATE[aes-s390x.S]=asm/aes-s390x.pl
|
||||
INCLUDE[aes-s390x.o]=..
|
||||
|
||||
GENERATE[aesni-xts-avx512.s]=asm/aesni-xts-avx512.pl
|
||||
|
||||
GENERATE[aes-c64xplus.S]=asm/aes-c64xplus.pl
|
||||
|
||||
GENERATE[vpaes-loongarch64.S]=asm/vpaes-loongarch64.pl
|
||||
INCLUDE[vpaes-loongarch64.o]=..
|
||||
@@ -0,0 +1,256 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2010-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
|
||||
$output = pop and open STDOUT,">$output";
|
||||
|
||||
print <<'___';
|
||||
.text
|
||||
|
||||
.set noat
|
||||
|
||||
.globl OPENSSL_cpuid_setup
|
||||
.ent OPENSSL_cpuid_setup
|
||||
OPENSSL_cpuid_setup:
|
||||
.frame $30,0,$26
|
||||
.prologue 0
|
||||
ret ($26)
|
||||
.end OPENSSL_cpuid_setup
|
||||
|
||||
.globl OPENSSL_wipe_cpu
|
||||
.ent OPENSSL_wipe_cpu
|
||||
OPENSSL_wipe_cpu:
|
||||
.frame $30,0,$26
|
||||
.prologue 0
|
||||
clr $1
|
||||
clr $2
|
||||
clr $3
|
||||
clr $4
|
||||
clr $5
|
||||
clr $6
|
||||
clr $7
|
||||
clr $8
|
||||
clr $16
|
||||
clr $17
|
||||
clr $18
|
||||
clr $19
|
||||
clr $20
|
||||
clr $21
|
||||
clr $22
|
||||
clr $23
|
||||
clr $24
|
||||
clr $25
|
||||
clr $27
|
||||
clr $at
|
||||
clr $29
|
||||
fclr $f0
|
||||
fclr $f1
|
||||
fclr $f10
|
||||
fclr $f11
|
||||
fclr $f12
|
||||
fclr $f13
|
||||
fclr $f14
|
||||
fclr $f15
|
||||
fclr $f16
|
||||
fclr $f17
|
||||
fclr $f18
|
||||
fclr $f19
|
||||
fclr $f20
|
||||
fclr $f21
|
||||
fclr $f22
|
||||
fclr $f23
|
||||
fclr $f24
|
||||
fclr $f25
|
||||
fclr $f26
|
||||
fclr $f27
|
||||
fclr $f28
|
||||
fclr $f29
|
||||
fclr $f30
|
||||
mov $sp,$0
|
||||
ret ($26)
|
||||
.end OPENSSL_wipe_cpu
|
||||
|
||||
.globl OPENSSL_atomic_add
|
||||
.ent OPENSSL_atomic_add
|
||||
OPENSSL_atomic_add:
|
||||
.frame $30,0,$26
|
||||
.prologue 0
|
||||
1: ldl_l $0,0($16)
|
||||
addl $0,$17,$1
|
||||
stl_c $1,0($16)
|
||||
beq $1,1b
|
||||
addl $0,$17,$0
|
||||
ret ($26)
|
||||
.end OPENSSL_atomic_add
|
||||
|
||||
.globl OPENSSL_rdtsc
|
||||
.ent OPENSSL_rdtsc
|
||||
OPENSSL_rdtsc:
|
||||
.frame $30,0,$26
|
||||
.prologue 0
|
||||
rpcc $0
|
||||
ret ($26)
|
||||
.end OPENSSL_rdtsc
|
||||
|
||||
.globl OPENSSL_cleanse
|
||||
.ent OPENSSL_cleanse
|
||||
OPENSSL_cleanse:
|
||||
.frame $30,0,$26
|
||||
.prologue 0
|
||||
beq $17,.Ldone
|
||||
and $16,7,$0
|
||||
bic $17,7,$at
|
||||
beq $at,.Little
|
||||
beq $0,.Laligned
|
||||
|
||||
.Little:
|
||||
subq $0,8,$0
|
||||
ldq_u $1,0($16)
|
||||
mov $16,$2
|
||||
.Lalign:
|
||||
mskbl $1,$16,$1
|
||||
lda $16,1($16)
|
||||
subq $17,1,$17
|
||||
addq $0,1,$0
|
||||
beq $17,.Lout
|
||||
bne $0,.Lalign
|
||||
.Lout: stq_u $1,0($2)
|
||||
beq $17,.Ldone
|
||||
bic $17,7,$at
|
||||
beq $at,.Little
|
||||
|
||||
.Laligned:
|
||||
stq $31,0($16)
|
||||
subq $17,8,$17
|
||||
lda $16,8($16)
|
||||
bic $17,7,$at
|
||||
bne $at,.Laligned
|
||||
bne $17,.Little
|
||||
.Ldone: ret ($26)
|
||||
.end OPENSSL_cleanse
|
||||
|
||||
.globl CRYPTO_memcmp
|
||||
.ent CRYPTO_memcmp
|
||||
CRYPTO_memcmp:
|
||||
.frame $30,0,$26
|
||||
.prologue 0
|
||||
xor $0,$0,$0
|
||||
beq $18,.Lno_data
|
||||
|
||||
xor $1,$1,$1
|
||||
nop
|
||||
.Loop_cmp:
|
||||
ldq_u $2,0($16)
|
||||
subq $18,1,$18
|
||||
ldq_u $3,0($17)
|
||||
extbl $2,$16,$2
|
||||
lda $16,1($16)
|
||||
extbl $3,$17,$3
|
||||
lda $17,1($17)
|
||||
xor $3,$2,$2
|
||||
or $2,$0,$0
|
||||
bne $18,.Loop_cmp
|
||||
|
||||
subq $31,$0,$0
|
||||
srl $0,63,$0
|
||||
.Lno_data:
|
||||
ret ($26)
|
||||
.end CRYPTO_memcmp
|
||||
___
|
||||
{
|
||||
my ($out,$cnt,$max)=("\$16","\$17","\$18");
|
||||
my ($tick,$lasttick)=("\$19","\$20");
|
||||
my ($diff,$lastdiff)=("\$21","\$22");
|
||||
my ($v0,$ra,$sp,$zero)=("\$0","\$26","\$30","\$31");
|
||||
|
||||
print <<___;
|
||||
.globl OPENSSL_instrument_bus
|
||||
.ent OPENSSL_instrument_bus
|
||||
OPENSSL_instrument_bus:
|
||||
.frame $sp,0,$ra
|
||||
.prologue 0
|
||||
mov $cnt,$v0
|
||||
|
||||
rpcc $lasttick
|
||||
mov 0,$diff
|
||||
|
||||
ecb ($out)
|
||||
ldl_l $tick,0($out)
|
||||
addl $diff,$tick,$tick
|
||||
mov $tick,$diff
|
||||
stl_c $tick,0($out)
|
||||
stl $diff,0($out)
|
||||
|
||||
.Loop: rpcc $tick
|
||||
subq $tick,$lasttick,$diff
|
||||
mov $tick,$lasttick
|
||||
|
||||
ecb ($out)
|
||||
ldl_l $tick,0($out)
|
||||
addl $diff,$tick,$tick
|
||||
mov $tick,$diff
|
||||
stl_c $tick,0($out)
|
||||
stl $diff,0($out)
|
||||
|
||||
subl $cnt,1,$cnt
|
||||
lda $out,4($out)
|
||||
bne $cnt,.Loop
|
||||
|
||||
ret ($ra)
|
||||
.end OPENSSL_instrument_bus
|
||||
|
||||
.globl OPENSSL_instrument_bus2
|
||||
.ent OPENSSL_instrument_bus2
|
||||
OPENSSL_instrument_bus2:
|
||||
.frame $sp,0,$ra
|
||||
.prologue 0
|
||||
mov $cnt,$v0
|
||||
|
||||
rpcc $lasttick
|
||||
mov 0,$diff
|
||||
|
||||
ecb ($out)
|
||||
ldl_l $tick,0($out)
|
||||
addl $diff,$tick,$tick
|
||||
mov $tick,$diff
|
||||
stl_c $tick,0($out)
|
||||
stl $diff,0($out)
|
||||
|
||||
rpcc $tick
|
||||
subq $tick,$lasttick,$diff
|
||||
mov $tick,$lasttick
|
||||
mov $diff,$lastdiff
|
||||
.Loop2:
|
||||
ecb ($out)
|
||||
ldl_l $tick,0($out)
|
||||
addl $diff,$tick,$tick
|
||||
mov $tick,$diff
|
||||
stl_c $tick,0($out)
|
||||
stl $diff,0($out)
|
||||
|
||||
subl $max,1,$max
|
||||
beq $max,.Ldone2
|
||||
|
||||
rpcc $tick
|
||||
subq $tick,$lasttick,$diff
|
||||
mov $tick,$lasttick
|
||||
subq $lastdiff,$diff,$tick
|
||||
mov $diff,$lastdiff
|
||||
cmovne $tick,1,$tick
|
||||
subl $cnt,$tick,$cnt
|
||||
s4addq $tick,$out,$out
|
||||
bne $cnt,.Loop2
|
||||
|
||||
.Ldone2:
|
||||
subl $v0,$cnt,$v0
|
||||
ret ($ra)
|
||||
.end OPENSSL_instrument_bus2
|
||||
___
|
||||
}
|
||||
|
||||
close STDOUT or die "error closing STDOUT: $!";
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
LIBS=../../libcrypto
|
||||
SOURCE[../../libcrypto]=\
|
||||
aria.c
|
||||
|
||||
@@ -0,0 +1,270 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
|
||||
# $output is the last argument if it looks like a file (it has an extension)
|
||||
# $flavour is the first argument if it doesn't look like a file
|
||||
$output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
|
||||
$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
die "can't locate arm-xlate.pl";
|
||||
|
||||
open OUT,"| \"$^X\" $xlate $flavour \"$output\""
|
||||
or die "can't call $xlate: $!";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
$code.=<<___;
|
||||
#include "arm_arch.h"
|
||||
|
||||
.text
|
||||
.arch armv8-a+crypto
|
||||
|
||||
.align 5
|
||||
.globl _armv7_neon_probe
|
||||
.type _armv7_neon_probe,%function
|
||||
_armv7_neon_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
orr v15.16b, v15.16b, v15.16b
|
||||
ret
|
||||
.size _armv7_neon_probe,.-_armv7_neon_probe
|
||||
|
||||
.globl _armv7_tick
|
||||
.type _armv7_tick,%function
|
||||
_armv7_tick:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
#ifdef __APPLE__
|
||||
mrs x0, CNTPCT_EL0
|
||||
#else
|
||||
mrs x0, CNTVCT_EL0
|
||||
#endif
|
||||
ret
|
||||
.size _armv7_tick,.-_armv7_tick
|
||||
|
||||
.globl _armv8_aes_probe
|
||||
.type _armv8_aes_probe,%function
|
||||
_armv8_aes_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
aese v0.16b, v0.16b
|
||||
ret
|
||||
.size _armv8_aes_probe,.-_armv8_aes_probe
|
||||
|
||||
.globl _armv8_sha1_probe
|
||||
.type _armv8_sha1_probe,%function
|
||||
_armv8_sha1_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
sha1h s0, s0
|
||||
ret
|
||||
.size _armv8_sha1_probe,.-_armv8_sha1_probe
|
||||
|
||||
.globl _armv8_sha256_probe
|
||||
.type _armv8_sha256_probe,%function
|
||||
_armv8_sha256_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
sha256su0 v0.4s, v0.4s
|
||||
ret
|
||||
.size _armv8_sha256_probe,.-_armv8_sha256_probe
|
||||
|
||||
.globl _armv8_pmull_probe
|
||||
.type _armv8_pmull_probe,%function
|
||||
_armv8_pmull_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
pmull v0.1q, v0.1d, v0.1d
|
||||
ret
|
||||
.size _armv8_pmull_probe,.-_armv8_pmull_probe
|
||||
|
||||
.globl _armv8_sm4_probe
|
||||
.type _armv8_sm4_probe,%function
|
||||
_armv8_sm4_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
.inst 0xcec08400 // sm4e v0.4s, v0.4s
|
||||
ret
|
||||
.size _armv8_sm4_probe,.-_armv8_sm4_probe
|
||||
|
||||
.globl _armv8_sha512_probe
|
||||
.type _armv8_sha512_probe,%function
|
||||
_armv8_sha512_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
.inst 0xcec08000 // sha512su0 v0.2d,v0.2d
|
||||
ret
|
||||
.size _armv8_sha512_probe,.-_armv8_sha512_probe
|
||||
|
||||
.globl _armv8_eor3_probe
|
||||
.type _armv8_eor3_probe,%function
|
||||
_armv8_eor3_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
.inst 0xce010800 // eor3 v0.16b, v0.16b, v1.16b, v2.16b
|
||||
ret
|
||||
.size _armv8_eor3_probe,.-_armv8_eor3_probe
|
||||
|
||||
.globl _armv8_sve_probe
|
||||
.type _armv8_sve_probe,%function
|
||||
_armv8_sve_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
.inst 0x04a03000 // eor z0.d,z0.d,z0.d
|
||||
ret
|
||||
.size _armv8_sve_probe,.-_armv8_sve_probe
|
||||
|
||||
.globl _armv8_sve2_probe
|
||||
.type _armv8_sve2_probe,%function
|
||||
_armv8_sve2_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
.inst 0x04e03400 // xar z0.d,z0.d,z0.d
|
||||
ret
|
||||
.size _armv8_sve2_probe,.-_armv8_sve2_probe
|
||||
|
||||
.globl _armv8_cpuid_probe
|
||||
.type _armv8_cpuid_probe,%function
|
||||
_armv8_cpuid_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
mrs x0, midr_el1
|
||||
ret
|
||||
.size _armv8_cpuid_probe,.-_armv8_cpuid_probe
|
||||
|
||||
.globl _armv8_sm3_probe
|
||||
.type _armv8_sm3_probe,%function
|
||||
_armv8_sm3_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
.inst 0xce63c004 // sm3partw1 v4.4s, v0.4s, v3.4s
|
||||
ret
|
||||
.size _armv8_sm3_probe,.-_armv8_sm3_probe
|
||||
|
||||
.globl OPENSSL_cleanse
|
||||
.type OPENSSL_cleanse,%function
|
||||
.align 5
|
||||
OPENSSL_cleanse:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
cbz x1,.Lret // len==0?
|
||||
cmp x1,#15
|
||||
b.hi .Lot // len>15
|
||||
nop
|
||||
.Little:
|
||||
strb wzr,[x0],#1 // store byte-by-byte
|
||||
subs x1,x1,#1
|
||||
b.ne .Little
|
||||
.Lret: ret
|
||||
|
||||
.align 4
|
||||
.Lot: tst x0,#7
|
||||
b.eq .Laligned // inp is aligned
|
||||
strb wzr,[x0],#1 // store byte-by-byte
|
||||
sub x1,x1,#1
|
||||
b .Lot
|
||||
|
||||
.align 4
|
||||
.Laligned:
|
||||
str xzr,[x0],#8 // store word-by-word
|
||||
sub x1,x1,#8
|
||||
tst x1,#-8
|
||||
b.ne .Laligned // len>=8
|
||||
cbnz x1,.Little // len!=0?
|
||||
ret
|
||||
.size OPENSSL_cleanse,.-OPENSSL_cleanse
|
||||
|
||||
.globl CRYPTO_memcmp
|
||||
.type CRYPTO_memcmp,%function
|
||||
.align 4
|
||||
CRYPTO_memcmp:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
eor w3,w3,w3
|
||||
cbz x2,.Lno_data // len==0?
|
||||
cmp x2,#16
|
||||
b.ne .Loop_cmp
|
||||
ldp x8,x9,[x0]
|
||||
ldp x10,x11,[x1]
|
||||
eor x8,x8,x10
|
||||
eor x9,x9,x11
|
||||
orr x8,x8,x9
|
||||
mov x0,#1
|
||||
cmp x8,#0
|
||||
csel x0,xzr,x0,eq
|
||||
ret
|
||||
|
||||
.align 4
|
||||
.Loop_cmp:
|
||||
ldrb w4,[x0],#1
|
||||
ldrb w5,[x1],#1
|
||||
eor w4,w4,w5
|
||||
orr w3,w3,w4
|
||||
subs x2,x2,#1
|
||||
b.ne .Loop_cmp
|
||||
|
||||
.Lno_data:
|
||||
neg w0,w3
|
||||
lsr w0,w0,#31
|
||||
ret
|
||||
.size CRYPTO_memcmp,.-CRYPTO_memcmp
|
||||
|
||||
.globl _armv8_rng_probe
|
||||
.type _armv8_rng_probe,%function
|
||||
_armv8_rng_probe:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
mrs x0, s3_3_c2_c4_0 // rndr
|
||||
mrs x0, s3_3_c2_c4_1 // rndrrs
|
||||
ret
|
||||
.size _armv8_rng_probe,.-_armv8_rng_probe
|
||||
___
|
||||
|
||||
sub gen_random {
|
||||
my $rdop = shift;
|
||||
my $rand_reg = $rdop eq "rndr" ? "s3_3_c2_c4_0" : "s3_3_c2_c4_1";
|
||||
|
||||
return <<___;
|
||||
// Fill buffer with Randomly Generated Bytes
|
||||
// inputs: char * in x0 - Pointer to buffer
|
||||
// size_t in x1 - Number of bytes to write to buffer
|
||||
// outputs: size_t in x0 - Number of bytes successfully written to buffer
|
||||
.globl OPENSSL_${rdop}_asm
|
||||
.type OPENSSL_${rdop}_asm,%function
|
||||
.align 4
|
||||
OPENSSL_${rdop}_asm:
|
||||
AARCH64_VALID_CALL_TARGET
|
||||
mov x2,xzr
|
||||
mov x3,xzr
|
||||
|
||||
.align 4
|
||||
.Loop_${rdop}:
|
||||
cmp x1,#0
|
||||
b.eq .${rdop}_done
|
||||
mov x3,xzr
|
||||
mrs x3,$rand_reg
|
||||
b.eq .${rdop}_done
|
||||
|
||||
cmp x1,#8
|
||||
b.lt .Loop_single_byte_${rdop}
|
||||
|
||||
str x3,[x0]
|
||||
add x0,x0,#8
|
||||
add x2,x2,#8
|
||||
subs x1,x1,#8
|
||||
b.ge .Loop_${rdop}
|
||||
|
||||
.align 4
|
||||
.Loop_single_byte_${rdop}:
|
||||
strb w3,[x0]
|
||||
lsr x3,x3,#8
|
||||
add x2,x2,#1
|
||||
add x0,x0,#1
|
||||
subs x1,x1,#1
|
||||
b.gt .Loop_single_byte_${rdop}
|
||||
|
||||
.align 4
|
||||
.${rdop}_done:
|
||||
mov x0,x2
|
||||
ret
|
||||
.size OPENSSL_${rdop}_asm,.-OPENSSL_${rdop}_asm
|
||||
___
|
||||
}
|
||||
|
||||
$code .= gen_random("rndr");
|
||||
$code .= gen_random("rndrrs");
|
||||
|
||||
print $code;
|
||||
close STDOUT or die "error closing STDOUT: $!";
|
||||
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright 2011-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#ifndef OSSL_CRYPTO_ARM_ARCH_H
|
||||
# define OSSL_CRYPTO_ARM_ARCH_H
|
||||
|
||||
# if !defined(__ARM_ARCH__)
|
||||
# if defined(__CC_ARM)
|
||||
# define __ARM_ARCH__ __TARGET_ARCH_ARM
|
||||
# if defined(__BIG_ENDIAN)
|
||||
# define __ARMEB__
|
||||
# else
|
||||
# define __ARMEL__
|
||||
# endif
|
||||
# elif defined(__GNUC__)
|
||||
# if defined(__aarch64__)
|
||||
# define __ARM_ARCH__ 8
|
||||
/*
|
||||
* Why doesn't gcc define __ARM_ARCH__? Instead it defines
|
||||
* bunch of below macros. See all_architectures[] table in
|
||||
* gcc/config/arm/arm.c. On a side note it defines
|
||||
* __ARMEL__/__ARMEB__ for little-/big-endian.
|
||||
*/
|
||||
# elif defined(__ARM_ARCH)
|
||||
# define __ARM_ARCH__ __ARM_ARCH
|
||||
# elif defined(__ARM_ARCH_8A__)
|
||||
# define __ARM_ARCH__ 8
|
||||
# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
|
||||
defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \
|
||||
defined(__ARM_ARCH_7EM__)
|
||||
# define __ARM_ARCH__ 7
|
||||
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
|
||||
defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \
|
||||
defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \
|
||||
defined(__ARM_ARCH_6T2__)
|
||||
# define __ARM_ARCH__ 6
|
||||
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
|
||||
defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \
|
||||
defined(__ARM_ARCH_5TEJ__)
|
||||
# define __ARM_ARCH__ 5
|
||||
# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||
# define __ARM_ARCH__ 4
|
||||
# else
|
||||
# error "unsupported ARM architecture"
|
||||
# endif
|
||||
# elif defined(__ARM_ARCH)
|
||||
# define __ARM_ARCH__ __ARM_ARCH
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(__ARM_MAX_ARCH__)
|
||||
# define __ARM_MAX_ARCH__ __ARM_ARCH__
|
||||
# endif
|
||||
|
||||
# if __ARM_MAX_ARCH__<__ARM_ARCH__
|
||||
# error "__ARM_MAX_ARCH__ can't be less than __ARM_ARCH__"
|
||||
# elif __ARM_MAX_ARCH__!=__ARM_ARCH__
|
||||
# if __ARM_ARCH__<7 && __ARM_MAX_ARCH__>=7 && defined(__ARMEB__)
|
||||
# error "can't build universal big-endian binary"
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef __ASSEMBLER__
|
||||
extern unsigned int OPENSSL_armcap_P;
|
||||
extern unsigned int OPENSSL_arm_midr;
|
||||
extern unsigned int OPENSSL_armv8_rsa_neonized;
|
||||
# endif
|
||||
|
||||
# define ARMV7_NEON (1<<0)
|
||||
# define ARMV7_TICK (1<<1)
|
||||
# define ARMV8_AES (1<<2)
|
||||
# define ARMV8_SHA1 (1<<3)
|
||||
# define ARMV8_SHA256 (1<<4)
|
||||
# define ARMV8_PMULL (1<<5)
|
||||
# define ARMV8_SHA512 (1<<6)
|
||||
# define ARMV8_CPUID (1<<7)
|
||||
# define ARMV8_RNG (1<<8)
|
||||
# define ARMV8_SM3 (1<<9)
|
||||
# define ARMV8_SM4 (1<<10)
|
||||
# define ARMV8_SHA3 (1<<11)
|
||||
# define ARMV8_UNROLL8_EOR3 (1<<12)
|
||||
# define ARMV8_SVE (1<<13)
|
||||
# define ARMV8_SVE2 (1<<14)
|
||||
# define ARMV8_HAVE_SHA3_AND_WORTH_USING (1<<15)
|
||||
# define ARMV8_UNROLL12_EOR3 (1<<16)
|
||||
|
||||
/*
|
||||
* MIDR_EL1 system register
|
||||
*
|
||||
* 63___ _ ___32_31___ _ ___24_23_____20_19_____16_15__ _ __4_3_______0
|
||||
* | | | | | | |
|
||||
* |RES0 | Implementer | Variant | Arch | PartNum |Revision|
|
||||
* |____ _ _____|_____ _ _____|_________|_______ _|____ _ ___|________|
|
||||
*
|
||||
*/
|
||||
|
||||
# define ARM_CPU_IMP_ARM 0x41
|
||||
# define HISI_CPU_IMP 0x48
|
||||
# define ARM_CPU_IMP_APPLE 0x61
|
||||
# define ARM_CPU_IMP_MICROSOFT 0x6D
|
||||
# define ARM_CPU_IMP_AMPERE 0xC0
|
||||
|
||||
# define ARM_CPU_PART_CORTEX_A72 0xD08
|
||||
# define ARM_CPU_PART_N1 0xD0C
|
||||
# define ARM_CPU_PART_V1 0xD40
|
||||
# define ARM_CPU_PART_N2 0xD49
|
||||
# define HISI_CPU_PART_KP920 0xD01
|
||||
# define ARM_CPU_PART_V2 0xD4F
|
||||
|
||||
# define APPLE_CPU_PART_M1_ICESTORM 0x022
|
||||
# define APPLE_CPU_PART_M1_FIRESTORM 0x023
|
||||
# define APPLE_CPU_PART_M1_ICESTORM_PRO 0x024
|
||||
# define APPLE_CPU_PART_M1_FIRESTORM_PRO 0x025
|
||||
# define APPLE_CPU_PART_M1_ICESTORM_MAX 0x028
|
||||
# define APPLE_CPU_PART_M1_FIRESTORM_MAX 0x029
|
||||
# define APPLE_CPU_PART_M2_BLIZZARD 0x032
|
||||
# define APPLE_CPU_PART_M2_AVALANCHE 0x033
|
||||
# define APPLE_CPU_PART_M2_BLIZZARD_PRO 0x034
|
||||
# define APPLE_CPU_PART_M2_AVALANCHE_PRO 0x035
|
||||
# define APPLE_CPU_PART_M2_BLIZZARD_MAX 0x038
|
||||
# define APPLE_CPU_PART_M2_AVALANCHE_MAX 0x039
|
||||
|
||||
# define MICROSOFT_CPU_PART_COBALT_100 0xD49
|
||||
|
||||
# define MIDR_PARTNUM_SHIFT 4
|
||||
# define MIDR_PARTNUM_MASK (0xfffU << MIDR_PARTNUM_SHIFT)
|
||||
# define MIDR_PARTNUM(midr) \
|
||||
(((midr) & MIDR_PARTNUM_MASK) >> MIDR_PARTNUM_SHIFT)
|
||||
|
||||
# define MIDR_IMPLEMENTER_SHIFT 24
|
||||
# define MIDR_IMPLEMENTER_MASK (0xffU << MIDR_IMPLEMENTER_SHIFT)
|
||||
# define MIDR_IMPLEMENTER(midr) \
|
||||
(((midr) & MIDR_IMPLEMENTER_MASK) >> MIDR_IMPLEMENTER_SHIFT)
|
||||
|
||||
# define MIDR_ARCHITECTURE_SHIFT 16
|
||||
# define MIDR_ARCHITECTURE_MASK (0xfU << MIDR_ARCHITECTURE_SHIFT)
|
||||
# define MIDR_ARCHITECTURE(midr) \
|
||||
(((midr) & MIDR_ARCHITECTURE_MASK) >> MIDR_ARCHITECTURE_SHIFT)
|
||||
|
||||
# define MIDR_CPU_MODEL_MASK \
|
||||
(MIDR_IMPLEMENTER_MASK | \
|
||||
MIDR_PARTNUM_MASK | \
|
||||
MIDR_ARCHITECTURE_MASK)
|
||||
|
||||
# define MIDR_CPU_MODEL(imp, partnum) \
|
||||
(((imp) << MIDR_IMPLEMENTER_SHIFT) | \
|
||||
(0xfU << MIDR_ARCHITECTURE_SHIFT) | \
|
||||
((partnum) << MIDR_PARTNUM_SHIFT))
|
||||
|
||||
# define MIDR_IS_CPU_MODEL(midr, imp, partnum) \
|
||||
(((midr) & MIDR_CPU_MODEL_MASK) == MIDR_CPU_MODEL(imp, partnum))
|
||||
|
||||
#if defined(__ASSEMBLER__)
|
||||
|
||||
/*
|
||||
* Support macros for
|
||||
* - Armv8.3-A Pointer Authentication and
|
||||
* - Armv8.5-A Branch Target Identification
|
||||
* features which require emitting a .note.gnu.property section with the
|
||||
* appropriate architecture-dependent feature bits set.
|
||||
* Read more: "ELF for the Arm® 64-bit Architecture"
|
||||
*/
|
||||
|
||||
# if defined(__ARM_FEATURE_BTI_DEFAULT) && __ARM_FEATURE_BTI_DEFAULT == 1
|
||||
# define GNU_PROPERTY_AARCH64_BTI (1 << 0) /* Has Branch Target Identification */
|
||||
# define AARCH64_VALID_CALL_TARGET hint #34 /* BTI 'c' */
|
||||
# else
|
||||
# define GNU_PROPERTY_AARCH64_BTI 0 /* No Branch Target Identification */
|
||||
# define AARCH64_VALID_CALL_TARGET
|
||||
# endif
|
||||
|
||||
# if defined(__ARM_FEATURE_PAC_DEFAULT) && \
|
||||
(__ARM_FEATURE_PAC_DEFAULT & 1) == 1 /* Signed with A-key */
|
||||
# define GNU_PROPERTY_AARCH64_POINTER_AUTH \
|
||||
(1 << 1) /* Has Pointer Authentication */
|
||||
# define AARCH64_SIGN_LINK_REGISTER hint #25 /* PACIASP */
|
||||
# define AARCH64_VALIDATE_LINK_REGISTER hint #29 /* AUTIASP */
|
||||
# elif defined(__ARM_FEATURE_PAC_DEFAULT) && \
|
||||
(__ARM_FEATURE_PAC_DEFAULT & 2) == 2 /* Signed with B-key */
|
||||
# define GNU_PROPERTY_AARCH64_POINTER_AUTH \
|
||||
(1 << 1) /* Has Pointer Authentication */
|
||||
# define AARCH64_SIGN_LINK_REGISTER hint #27 /* PACIBSP */
|
||||
# define AARCH64_VALIDATE_LINK_REGISTER hint #31 /* AUTIBSP */
|
||||
# else
|
||||
# define GNU_PROPERTY_AARCH64_POINTER_AUTH 0 /* No Pointer Authentication */
|
||||
# if GNU_PROPERTY_AARCH64_BTI != 0
|
||||
# define AARCH64_SIGN_LINK_REGISTER AARCH64_VALID_CALL_TARGET
|
||||
# else
|
||||
# define AARCH64_SIGN_LINK_REGISTER
|
||||
# endif
|
||||
# define AARCH64_VALIDATE_LINK_REGISTER
|
||||
# endif
|
||||
|
||||
# if GNU_PROPERTY_AARCH64_POINTER_AUTH != 0 || GNU_PROPERTY_AARCH64_BTI != 0
|
||||
.pushsection .note.gnu.property, "a";
|
||||
.balign 8;
|
||||
.long 4;
|
||||
.long 0x10;
|
||||
.long 0x5;
|
||||
.asciz "GNU";
|
||||
.long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
|
||||
.long 4;
|
||||
.long (GNU_PROPERTY_AARCH64_POINTER_AUTH | GNU_PROPERTY_AARCH64_BTI);
|
||||
.long 0;
|
||||
.popsection;
|
||||
# endif
|
||||
|
||||
# endif /* defined __ASSEMBLER__ */
|
||||
|
||||
# define IS_CPU_SUPPORT_UNROLL8_EOR3() \
|
||||
(OPENSSL_armcap_P & ARMV8_UNROLL8_EOR3)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright 2011-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <openssl/crypto.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/sysctl.h>
|
||||
#else
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
#include "internal/cryptlib.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "arm_arch.h"
|
||||
|
||||
unsigned int OPENSSL_armcap_P = 0;
|
||||
unsigned int OPENSSL_arm_midr = 0;
|
||||
unsigned int OPENSSL_armv8_rsa_neonized = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
void OPENSSL_cpuid_setup(void)
|
||||
{
|
||||
OPENSSL_armcap_P |= ARMV7_NEON;
|
||||
OPENSSL_armv8_rsa_neonized = 1;
|
||||
if (IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)) {
|
||||
/* These are all covered by one call in Windows */
|
||||
OPENSSL_armcap_P |= ARMV8_AES;
|
||||
OPENSSL_armcap_P |= ARMV8_PMULL;
|
||||
OPENSSL_armcap_P |= ARMV8_SHA1;
|
||||
OPENSSL_armcap_P |= ARMV8_SHA256;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t OPENSSL_rdtsc(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#elif __ARM_MAX_ARCH__ < 7
|
||||
void OPENSSL_cpuid_setup(void)
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t OPENSSL_rdtsc(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else /* !_WIN32 && __ARM_MAX_ARCH__ >= 7 */
|
||||
|
||||
/* 3 ways of handling things here: __APPLE__, getauxval() or SIGILL detect */
|
||||
|
||||
/* First determine if getauxval() is available (OSSL_IMPLEMENT_GETAUXVAL) */
|
||||
|
||||
# if defined(__GNUC__) && __GNUC__>=2
|
||||
void OPENSSL_cpuid_setup(void) __attribute__ ((constructor));
|
||||
# endif
|
||||
|
||||
# if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
|
||||
# if __GLIBC_PREREQ(2, 16)
|
||||
# include <sys/auxv.h>
|
||||
# define OSSL_IMPLEMENT_GETAUXVAL
|
||||
# endif
|
||||
# elif defined(__ANDROID_API__)
|
||||
/* see https://developer.android.google.cn/ndk/guides/cpu-features */
|
||||
# if __ANDROID_API__ >= 18
|
||||
# include <sys/auxv.h>
|
||||
# define OSSL_IMPLEMENT_GETAUXVAL
|
||||
# endif
|
||||
# endif
|
||||
# if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||
# include <sys/param.h>
|
||||
# if (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || \
|
||||
(defined(__OpenBSD__) && OpenBSD >= 202409)
|
||||
# include <sys/auxv.h>
|
||||
# define OSSL_IMPLEMENT_GETAUXVAL
|
||||
|
||||
static unsigned long getauxval(unsigned long key)
|
||||
{
|
||||
unsigned long val = 0ul;
|
||||
|
||||
if (elf_aux_info((int)key, &val, sizeof(val)) != 0)
|
||||
return 0ul;
|
||||
|
||||
return val;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Android: according to https://developer.android.com/ndk/guides/cpu-features,
|
||||
* getauxval is supported starting with API level 18
|
||||
*/
|
||||
# if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 18
|
||||
# include <sys/auxv.h>
|
||||
# define OSSL_IMPLEMENT_GETAUXVAL
|
||||
# endif
|
||||
|
||||
/*
|
||||
* ARM puts the feature bits for Crypto Extensions in AT_HWCAP2, whereas
|
||||
* AArch64 used AT_HWCAP.
|
||||
*/
|
||||
# ifndef AT_HWCAP
|
||||
# define AT_HWCAP 16
|
||||
# endif
|
||||
# ifndef AT_HWCAP2
|
||||
# define AT_HWCAP2 26
|
||||
# endif
|
||||
# if defined(__arm__) || defined (__arm)
|
||||
# define OSSL_HWCAP AT_HWCAP
|
||||
# define OSSL_HWCAP_NEON (1 << 12)
|
||||
|
||||
# define OSSL_HWCAP_CE AT_HWCAP2
|
||||
# define OSSL_HWCAP_CE_AES (1 << 0)
|
||||
# define OSSL_HWCAP_CE_PMULL (1 << 1)
|
||||
# define OSSL_HWCAP_CE_SHA1 (1 << 2)
|
||||
# define OSSL_HWCAP_CE_SHA256 (1 << 3)
|
||||
# elif defined(__aarch64__)
|
||||
# define OSSL_HWCAP AT_HWCAP
|
||||
# define OSSL_HWCAP_NEON (1 << 1)
|
||||
|
||||
# define OSSL_HWCAP_CE AT_HWCAP
|
||||
# define OSSL_HWCAP_CE_AES (1 << 3)
|
||||
# define OSSL_HWCAP_CE_PMULL (1 << 4)
|
||||
# define OSSL_HWCAP_CE_SHA1 (1 << 5)
|
||||
# define OSSL_HWCAP_CE_SHA256 (1 << 6)
|
||||
# define OSSL_HWCAP_CPUID (1 << 11)
|
||||
# define OSSL_HWCAP_SHA3 (1 << 17)
|
||||
# define OSSL_HWCAP_CE_SM3 (1 << 18)
|
||||
# define OSSL_HWCAP_CE_SM4 (1 << 19)
|
||||
# define OSSL_HWCAP_CE_SHA512 (1 << 21)
|
||||
# define OSSL_HWCAP_SVE (1 << 22)
|
||||
/* AT_HWCAP2 */
|
||||
# define OSSL_HWCAP2 26
|
||||
# define OSSL_HWCAP2_SVE2 (1 << 1)
|
||||
# define OSSL_HWCAP2_RNG (1 << 16)
|
||||
# endif
|
||||
|
||||
uint32_t _armv7_tick(void);
|
||||
|
||||
uint32_t OPENSSL_rdtsc(void)
|
||||
{
|
||||
if (OPENSSL_armcap_P & ARMV7_TICK)
|
||||
return _armv7_tick();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
# ifdef __aarch64__
|
||||
size_t OPENSSL_rndr_asm(unsigned char *buf, size_t len);
|
||||
size_t OPENSSL_rndrrs_asm(unsigned char *buf, size_t len);
|
||||
|
||||
size_t OPENSSL_rndr_bytes(unsigned char *buf, size_t len);
|
||||
size_t OPENSSL_rndrrs_bytes(unsigned char *buf, size_t len);
|
||||
|
||||
static size_t OPENSSL_rndr_wrapper(size_t (*func)(unsigned char *, size_t), unsigned char *buf, size_t len)
|
||||
{
|
||||
size_t buffer_size = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
buffer_size = func(buf, len);
|
||||
if (buffer_size == len)
|
||||
break;
|
||||
usleep(5000); /* 5000 microseconds (5 milliseconds) */
|
||||
}
|
||||
return buffer_size;
|
||||
}
|
||||
|
||||
size_t OPENSSL_rndr_bytes(unsigned char *buf, size_t len)
|
||||
{
|
||||
return OPENSSL_rndr_wrapper(OPENSSL_rndr_asm, buf, len);
|
||||
}
|
||||
|
||||
size_t OPENSSL_rndrrs_bytes(unsigned char *buf, size_t len)
|
||||
{
|
||||
return OPENSSL_rndr_wrapper(OPENSSL_rndrrs_asm, buf, len);
|
||||
}
|
||||
# endif
|
||||
|
||||
# if !defined(__APPLE__) && !defined(OSSL_IMPLEMENT_GETAUXVAL)
|
||||
static sigset_t all_masked;
|
||||
|
||||
static sigjmp_buf ill_jmp;
|
||||
static void ill_handler(int sig)
|
||||
{
|
||||
siglongjmp(ill_jmp, sig);
|
||||
}
|
||||
|
||||
/*
|
||||
* Following subroutines could have been inlined, but not all
|
||||
* ARM compilers support inline assembler, and we'd then have to
|
||||
* worry about the compiler optimising out the detection code...
|
||||
*/
|
||||
void _armv7_neon_probe(void);
|
||||
void _armv8_aes_probe(void);
|
||||
void _armv8_sha1_probe(void);
|
||||
void _armv8_sha256_probe(void);
|
||||
void _armv8_pmull_probe(void);
|
||||
# ifdef __aarch64__
|
||||
void _armv8_sm3_probe(void);
|
||||
void _armv8_sm4_probe(void);
|
||||
void _armv8_sha512_probe(void);
|
||||
void _armv8_eor3_probe(void);
|
||||
void _armv8_sve_probe(void);
|
||||
void _armv8_sve2_probe(void);
|
||||
void _armv8_rng_probe(void);
|
||||
# endif
|
||||
# endif /* !__APPLE__ && !OSSL_IMPLEMENT_GETAUXVAL */
|
||||
|
||||
/* We only call _armv8_cpuid_probe() if (OPENSSL_armcap_P & ARMV8_CPUID) != 0 */
|
||||
unsigned int _armv8_cpuid_probe(void);
|
||||
|
||||
# if defined(__APPLE__)
|
||||
/*
|
||||
* Checks the specified integer sysctl, returning `value` if it's 1, otherwise returning 0.
|
||||
*/
|
||||
static unsigned int sysctl_query(const char *name, unsigned int value)
|
||||
{
|
||||
unsigned int sys_value = 0;
|
||||
size_t len = sizeof(sys_value);
|
||||
|
||||
return (sysctlbyname(name, &sys_value, &len, NULL, 0) == 0 && sys_value == 1) ? value : 0;
|
||||
}
|
||||
# elif !defined(OSSL_IMPLEMENT_GETAUXVAL)
|
||||
/*
|
||||
* Calls a provided probe function, which may SIGILL. If it doesn't, return `value`, otherwise return 0.
|
||||
*/
|
||||
static unsigned int arm_probe_for(void (*probe)(void), volatile unsigned int value)
|
||||
{
|
||||
if (sigsetjmp(ill_jmp, 1) == 0) {
|
||||
probe();
|
||||
return value;
|
||||
} else {
|
||||
/* The probe function gave us SIGILL */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
void OPENSSL_cpuid_setup(void)
|
||||
{
|
||||
const char *e;
|
||||
# if !defined(__APPLE__) && !defined(OSSL_IMPLEMENT_GETAUXVAL)
|
||||
struct sigaction ill_oact, ill_act;
|
||||
sigset_t oset;
|
||||
# endif
|
||||
static int trigger = 0;
|
||||
|
||||
if (trigger)
|
||||
return;
|
||||
trigger = 1;
|
||||
|
||||
OPENSSL_armcap_P = 0;
|
||||
|
||||
if ((e = getenv("OPENSSL_armcap"))) {
|
||||
OPENSSL_armcap_P = (unsigned int)strtoul(e, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
# if defined(__APPLE__)
|
||||
# if !defined(__aarch64__)
|
||||
/*
|
||||
* Capability probing by catching SIGILL appears to be problematic
|
||||
* on iOS. But since Apple universe is "monocultural", it's actually
|
||||
* possible to simply set pre-defined processor capability mask.
|
||||
*/
|
||||
if (1) {
|
||||
OPENSSL_armcap_P = ARMV7_NEON;
|
||||
return;
|
||||
}
|
||||
# else
|
||||
{
|
||||
/*
|
||||
* From
|
||||
* https://github.com/llvm/llvm-project/blob/412237dcd07e5a2afbb1767858262a5f037149a3/llvm/lib/Target/AArch64/AArch64.td#L719
|
||||
* all of these have been available on 64-bit Apple Silicon from the
|
||||
* beginning (the A7).
|
||||
*/
|
||||
OPENSSL_armcap_P |= ARMV7_NEON | ARMV8_PMULL | ARMV8_AES | ARMV8_SHA1 | ARMV8_SHA256;
|
||||
|
||||
/* More recent extensions are indicated by sysctls */
|
||||
OPENSSL_armcap_P |= sysctl_query("hw.optional.armv8_2_sha512", ARMV8_SHA512);
|
||||
OPENSSL_armcap_P |= sysctl_query("hw.optional.armv8_2_sha3", ARMV8_SHA3);
|
||||
|
||||
if (OPENSSL_armcap_P & ARMV8_SHA3) {
|
||||
char uarch[64];
|
||||
|
||||
size_t len = sizeof(uarch);
|
||||
if ((sysctlbyname("machdep.cpu.brand_string", uarch, &len, NULL, 0) == 0) &&
|
||||
((strncmp(uarch, "Apple M1", 8) == 0) ||
|
||||
(strncmp(uarch, "Apple M2", 8) == 0) ||
|
||||
(strncmp(uarch, "Apple M3", 8) == 0) ||
|
||||
(strncmp(uarch, "Apple M4", 8) == 0))) {
|
||||
OPENSSL_armcap_P |= ARMV8_UNROLL8_EOR3;
|
||||
OPENSSL_armcap_P |= ARMV8_HAVE_SHA3_AND_WORTH_USING;
|
||||
}
|
||||
}
|
||||
}
|
||||
# endif /* __aarch64__ */
|
||||
|
||||
# elif defined(OSSL_IMPLEMENT_GETAUXVAL)
|
||||
|
||||
if (getauxval(OSSL_HWCAP) & OSSL_HWCAP_NEON) {
|
||||
unsigned long hwcap = getauxval(OSSL_HWCAP_CE);
|
||||
|
||||
OPENSSL_armcap_P |= ARMV7_NEON;
|
||||
|
||||
if (hwcap & OSSL_HWCAP_CE_AES)
|
||||
OPENSSL_armcap_P |= ARMV8_AES;
|
||||
|
||||
if (hwcap & OSSL_HWCAP_CE_PMULL)
|
||||
OPENSSL_armcap_P |= ARMV8_PMULL;
|
||||
|
||||
if (hwcap & OSSL_HWCAP_CE_SHA1)
|
||||
OPENSSL_armcap_P |= ARMV8_SHA1;
|
||||
|
||||
if (hwcap & OSSL_HWCAP_CE_SHA256)
|
||||
OPENSSL_armcap_P |= ARMV8_SHA256;
|
||||
|
||||
# ifdef __aarch64__
|
||||
if (hwcap & OSSL_HWCAP_CE_SM4)
|
||||
OPENSSL_armcap_P |= ARMV8_SM4;
|
||||
|
||||
if (hwcap & OSSL_HWCAP_CE_SHA512)
|
||||
OPENSSL_armcap_P |= ARMV8_SHA512;
|
||||
|
||||
if (hwcap & OSSL_HWCAP_CPUID)
|
||||
OPENSSL_armcap_P |= ARMV8_CPUID;
|
||||
|
||||
if (hwcap & OSSL_HWCAP_CE_SM3)
|
||||
OPENSSL_armcap_P |= ARMV8_SM3;
|
||||
if (hwcap & OSSL_HWCAP_SHA3)
|
||||
OPENSSL_armcap_P |= ARMV8_SHA3;
|
||||
# endif
|
||||
}
|
||||
# ifdef __aarch64__
|
||||
if (getauxval(OSSL_HWCAP) & OSSL_HWCAP_SVE)
|
||||
OPENSSL_armcap_P |= ARMV8_SVE;
|
||||
|
||||
if (getauxval(OSSL_HWCAP2) & OSSL_HWCAP2_SVE2)
|
||||
OPENSSL_armcap_P |= ARMV8_SVE2;
|
||||
|
||||
if (getauxval(OSSL_HWCAP2) & OSSL_HWCAP2_RNG)
|
||||
OPENSSL_armcap_P |= ARMV8_RNG;
|
||||
# endif
|
||||
|
||||
# else /* !__APPLE__ && !OSSL_IMPLEMENT_GETAUXVAL */
|
||||
|
||||
/* If all else fails, do brute force SIGILL-based feature detection */
|
||||
|
||||
sigfillset(&all_masked);
|
||||
sigdelset(&all_masked, SIGILL);
|
||||
sigdelset(&all_masked, SIGTRAP);
|
||||
sigdelset(&all_masked, SIGFPE);
|
||||
sigdelset(&all_masked, SIGBUS);
|
||||
sigdelset(&all_masked, SIGSEGV);
|
||||
|
||||
memset(&ill_act, 0, sizeof(ill_act));
|
||||
ill_act.sa_handler = ill_handler;
|
||||
ill_act.sa_mask = all_masked;
|
||||
|
||||
sigprocmask(SIG_SETMASK, &ill_act.sa_mask, &oset);
|
||||
sigaction(SIGILL, &ill_act, &ill_oact);
|
||||
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv7_neon_probe, ARMV7_NEON);
|
||||
|
||||
if (OPENSSL_armcap_P & ARMV7_NEON) {
|
||||
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_pmull_probe, ARMV8_PMULL | ARMV8_AES);
|
||||
if (!(OPENSSL_armcap_P & ARMV8_AES)) {
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_aes_probe, ARMV8_AES);
|
||||
}
|
||||
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_sha1_probe, ARMV8_SHA1);
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_sha256_probe, ARMV8_SHA256);
|
||||
|
||||
# if defined(__aarch64__)
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_sm3_probe, ARMV8_SM3);
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_sm4_probe, ARMV8_SM4);
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_sha512_probe, ARMV8_SHA512);
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_eor3_probe, ARMV8_SHA3);
|
||||
# endif
|
||||
}
|
||||
# ifdef __aarch64__
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_sve_probe, ARMV8_SVE);
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_sve2_probe, ARMV8_SVE2);
|
||||
OPENSSL_armcap_P |= arm_probe_for(_armv8_rng_probe, ARMV8_RNG);
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Probing for ARMV7_TICK is known to produce unreliable results,
|
||||
* so we only use the feature when the user explicitly enables it
|
||||
* with OPENSSL_armcap.
|
||||
*/
|
||||
|
||||
sigaction(SIGILL, &ill_oact, NULL);
|
||||
sigprocmask(SIG_SETMASK, &oset, NULL);
|
||||
|
||||
# endif /* __APPLE__, OSSL_IMPLEMENT_GETAUXVAL */
|
||||
|
||||
# ifdef __aarch64__
|
||||
if (OPENSSL_armcap_P & ARMV8_CPUID)
|
||||
OPENSSL_arm_midr = _armv8_cpuid_probe();
|
||||
|
||||
if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N1)) &&
|
||||
(OPENSSL_armcap_P & ARMV7_NEON)) {
|
||||
OPENSSL_armv8_rsa_neonized = 1;
|
||||
}
|
||||
if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_N2) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_MICROSOFT, MICROSOFT_CPU_PART_COBALT_100) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) ||
|
||||
MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE) &&
|
||||
(OPENSSL_armcap_P & ARMV8_SHA3))
|
||||
OPENSSL_armcap_P |= ARMV8_UNROLL8_EOR3;
|
||||
if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V1) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_ARM, ARM_CPU_PART_V2) ||
|
||||
MIDR_IMPLEMENTER(OPENSSL_arm_midr) == ARM_CPU_IMP_AMPERE) &&
|
||||
(OPENSSL_armcap_P & ARMV8_SHA3))
|
||||
OPENSSL_armcap_P |= ARMV8_UNROLL12_EOR3;
|
||||
if ((MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_PRO) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_PRO) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_FIRESTORM_MAX) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M1_ICESTORM_MAX) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_PRO) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_PRO) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_AVALANCHE_MAX) ||
|
||||
MIDR_IS_CPU_MODEL(OPENSSL_arm_midr, ARM_CPU_IMP_APPLE, APPLE_CPU_PART_M2_BLIZZARD_MAX)) &&
|
||||
(OPENSSL_armcap_P & ARMV8_SHA3))
|
||||
OPENSSL_armcap_P |= ARMV8_HAVE_SHA3_AND_WORTH_USING;
|
||||
# endif
|
||||
}
|
||||
#endif /* _WIN32, __ARM_MAX_ARCH__ >= 7 */
|
||||
@@ -0,0 +1,300 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2015-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
|
||||
# $output is the last argument if it looks like a file (it has an extension)
|
||||
# $flavour is the first argument if it doesn't look like a file
|
||||
$output = $#ARGV >= 0 && $ARGV[$#ARGV] =~ m|\.\w+$| ? pop : undef;
|
||||
$flavour = $#ARGV >= 0 && $ARGV[0] !~ m|\.| ? shift : undef;
|
||||
|
||||
$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
|
||||
( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or
|
||||
( $xlate="${dir}perlasm/arm-xlate.pl" and -f $xlate) or
|
||||
die "can't locate arm-xlate.pl";
|
||||
|
||||
open OUT,"| \"$^X\" $xlate $flavour \"$output\""
|
||||
or die "can't call $xlate: $!";
|
||||
*STDOUT=*OUT;
|
||||
|
||||
$code.=<<___;
|
||||
#include "arm_arch.h"
|
||||
|
||||
#if defined(__thumb2__) && !defined(__APPLE__)
|
||||
.syntax unified
|
||||
.thumb
|
||||
#else
|
||||
.code 32
|
||||
#undef __thumb2__
|
||||
#endif
|
||||
|
||||
.text
|
||||
|
||||
.align 5
|
||||
.global OPENSSL_atomic_add
|
||||
.type OPENSSL_atomic_add,%function
|
||||
OPENSSL_atomic_add:
|
||||
#if __ARM_ARCH__>=6
|
||||
.Ladd: ldrex r2,[r0]
|
||||
add r3,r2,r1
|
||||
strex r2,r3,[r0]
|
||||
cmp r2,#0
|
||||
bne .Ladd
|
||||
mov r0,r3
|
||||
bx lr
|
||||
#else
|
||||
stmdb sp!,{r4-r6,lr}
|
||||
ldr r2,.Lspinlock
|
||||
adr r3,.Lspinlock
|
||||
mov r4,r0
|
||||
mov r5,r1
|
||||
add r6,r3,r2 @ &spinlock
|
||||
b .+8
|
||||
.Lspin: bl sched_yield
|
||||
mov r0,#-1
|
||||
swp r0,r0,[r6]
|
||||
cmp r0,#0
|
||||
bne .Lspin
|
||||
|
||||
ldr r2,[r4]
|
||||
add r2,r2,r5
|
||||
str r2,[r4]
|
||||
str r0,[r6] @ release spinlock
|
||||
ldmia sp!,{r4-r6,lr}
|
||||
tst lr,#1
|
||||
moveq pc,lr
|
||||
.word 0xe12fff1e @ bx lr
|
||||
#endif
|
||||
.size OPENSSL_atomic_add,.-OPENSSL_atomic_add
|
||||
|
||||
.global OPENSSL_cleanse
|
||||
.type OPENSSL_cleanse,%function
|
||||
OPENSSL_cleanse:
|
||||
eor ip,ip,ip
|
||||
cmp r1,#7
|
||||
#ifdef __thumb2__
|
||||
itt hs
|
||||
#endif
|
||||
subhs r1,r1,#4
|
||||
bhs .Lot
|
||||
cmp r1,#0
|
||||
beq .Lcleanse_done
|
||||
.Little:
|
||||
strb ip,[r0],#1
|
||||
subs r1,r1,#1
|
||||
bhi .Little
|
||||
b .Lcleanse_done
|
||||
|
||||
.Lot: tst r0,#3
|
||||
beq .Laligned
|
||||
strb ip,[r0],#1
|
||||
sub r1,r1,#1
|
||||
b .Lot
|
||||
.Laligned:
|
||||
str ip,[r0],#4
|
||||
subs r1,r1,#4
|
||||
bhs .Laligned
|
||||
adds r1,r1,#4
|
||||
bne .Little
|
||||
.Lcleanse_done:
|
||||
#if __ARM_ARCH__>=5
|
||||
bx lr
|
||||
#else
|
||||
tst lr,#1
|
||||
moveq pc,lr
|
||||
.word 0xe12fff1e @ bx lr
|
||||
#endif
|
||||
.size OPENSSL_cleanse,.-OPENSSL_cleanse
|
||||
|
||||
.global CRYPTO_memcmp
|
||||
.type CRYPTO_memcmp,%function
|
||||
.align 4
|
||||
CRYPTO_memcmp:
|
||||
eor ip,ip,ip
|
||||
cmp r2,#0
|
||||
beq .Lno_data
|
||||
stmdb sp!,{r4,r5}
|
||||
|
||||
.Loop_cmp:
|
||||
ldrb r4,[r0],#1
|
||||
ldrb r5,[r1],#1
|
||||
eor r4,r4,r5
|
||||
orr ip,ip,r4
|
||||
subs r2,r2,#1
|
||||
bne .Loop_cmp
|
||||
|
||||
ldmia sp!,{r4,r5}
|
||||
.Lno_data:
|
||||
rsb r0,ip,#0
|
||||
mov r0,r0,lsr#31
|
||||
#if __ARM_ARCH__>=5
|
||||
bx lr
|
||||
#else
|
||||
tst lr,#1
|
||||
moveq pc,lr
|
||||
.word 0xe12fff1e @ bx lr
|
||||
#endif
|
||||
.size CRYPTO_memcmp,.-CRYPTO_memcmp
|
||||
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
.arch armv7-a
|
||||
.fpu neon
|
||||
|
||||
.align 5
|
||||
.global _armv7_neon_probe
|
||||
.type _armv7_neon_probe,%function
|
||||
_armv7_neon_probe:
|
||||
vorr q0,q0,q0
|
||||
bx lr
|
||||
.size _armv7_neon_probe,.-_armv7_neon_probe
|
||||
|
||||
.global _armv7_tick
|
||||
.type _armv7_tick,%function
|
||||
_armv7_tick:
|
||||
#ifdef __APPLE__
|
||||
mrrc p15,0,r0,r1,c14 @ CNTPCT
|
||||
#else
|
||||
mrrc p15,1,r0,r1,c14 @ CNTVCT
|
||||
#endif
|
||||
bx lr
|
||||
.size _armv7_tick,.-_armv7_tick
|
||||
|
||||
.global _armv8_aes_probe
|
||||
.type _armv8_aes_probe,%function
|
||||
_armv8_aes_probe:
|
||||
#if defined(__thumb2__) && !defined(__APPLE__)
|
||||
.byte 0xb0,0xff,0x00,0x03 @ aese.8 q0,q0
|
||||
#else
|
||||
.byte 0x00,0x03,0xb0,0xf3 @ aese.8 q0,q0
|
||||
#endif
|
||||
bx lr
|
||||
.size _armv8_aes_probe,.-_armv8_aes_probe
|
||||
|
||||
.global _armv8_sha1_probe
|
||||
.type _armv8_sha1_probe,%function
|
||||
_armv8_sha1_probe:
|
||||
#if defined(__thumb2__) && !defined(__APPLE__)
|
||||
.byte 0x00,0xef,0x40,0x0c @ sha1c.32 q0,q0,q0
|
||||
#else
|
||||
.byte 0x40,0x0c,0x00,0xf2 @ sha1c.32 q0,q0,q0
|
||||
#endif
|
||||
bx lr
|
||||
.size _armv8_sha1_probe,.-_armv8_sha1_probe
|
||||
|
||||
.global _armv8_sha256_probe
|
||||
.type _armv8_sha256_probe,%function
|
||||
_armv8_sha256_probe:
|
||||
#if defined(__thumb2__) && !defined(__APPLE__)
|
||||
.byte 0x00,0xff,0x40,0x0c @ sha256h.32 q0,q0,q0
|
||||
#else
|
||||
.byte 0x40,0x0c,0x00,0xf3 @ sha256h.32 q0,q0,q0
|
||||
#endif
|
||||
bx lr
|
||||
.size _armv8_sha256_probe,.-_armv8_sha256_probe
|
||||
.global _armv8_pmull_probe
|
||||
.type _armv8_pmull_probe,%function
|
||||
_armv8_pmull_probe:
|
||||
#if defined(__thumb2__) && !defined(__APPLE__)
|
||||
.byte 0xa0,0xef,0x00,0x0e @ vmull.p64 q0,d0,d0
|
||||
#else
|
||||
.byte 0x00,0x0e,0xa0,0xf2 @ vmull.p64 q0,d0,d0
|
||||
#endif
|
||||
bx lr
|
||||
.size _armv8_pmull_probe,.-_armv8_pmull_probe
|
||||
#endif
|
||||
|
||||
.global OPENSSL_wipe_cpu
|
||||
.type OPENSSL_wipe_cpu,%function
|
||||
OPENSSL_wipe_cpu:
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
ldr r0,.LOPENSSL_armcap
|
||||
adr r1,.LOPENSSL_armcap
|
||||
ldr r0,[r1,r0]
|
||||
#ifdef __APPLE__
|
||||
ldr r0,[r0]
|
||||
#endif
|
||||
#endif
|
||||
eor r2,r2,r2
|
||||
eor r3,r3,r3
|
||||
eor ip,ip,ip
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
tst r0,#1
|
||||
beq .Lwipe_done
|
||||
veor q0, q0, q0
|
||||
veor q1, q1, q1
|
||||
veor q2, q2, q2
|
||||
veor q3, q3, q3
|
||||
veor q8, q8, q8
|
||||
veor q9, q9, q9
|
||||
veor q10, q10, q10
|
||||
veor q11, q11, q11
|
||||
veor q12, q12, q12
|
||||
veor q13, q13, q13
|
||||
veor q14, q14, q14
|
||||
veor q15, q15, q15
|
||||
.Lwipe_done:
|
||||
#endif
|
||||
mov r0,sp
|
||||
#if __ARM_ARCH__>=5
|
||||
bx lr
|
||||
#else
|
||||
tst lr,#1
|
||||
moveq pc,lr
|
||||
.word 0xe12fff1e @ bx lr
|
||||
#endif
|
||||
.size OPENSSL_wipe_cpu,.-OPENSSL_wipe_cpu
|
||||
|
||||
.global OPENSSL_instrument_bus
|
||||
.type OPENSSL_instrument_bus,%function
|
||||
OPENSSL_instrument_bus:
|
||||
eor r0,r0,r0
|
||||
#if __ARM_ARCH__>=5
|
||||
bx lr
|
||||
#else
|
||||
tst lr,#1
|
||||
moveq pc,lr
|
||||
.word 0xe12fff1e @ bx lr
|
||||
#endif
|
||||
.size OPENSSL_instrument_bus,.-OPENSSL_instrument_bus
|
||||
|
||||
.global OPENSSL_instrument_bus2
|
||||
.type OPENSSL_instrument_bus2,%function
|
||||
OPENSSL_instrument_bus2:
|
||||
eor r0,r0,r0
|
||||
#if __ARM_ARCH__>=5
|
||||
bx lr
|
||||
#else
|
||||
tst lr,#1
|
||||
moveq pc,lr
|
||||
.word 0xe12fff1e @ bx lr
|
||||
#endif
|
||||
.size OPENSSL_instrument_bus2,.-OPENSSL_instrument_bus2
|
||||
|
||||
.align 5
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
.LOPENSSL_armcap:
|
||||
.word OPENSSL_armcap_P-.
|
||||
#endif
|
||||
#if __ARM_ARCH__>=6
|
||||
.align 5
|
||||
#else
|
||||
.Lspinlock:
|
||||
.word atomic_add_spinlock-.Lspinlock
|
||||
.align 5
|
||||
|
||||
.data
|
||||
.align 2
|
||||
atomic_add_spinlock:
|
||||
.word 0
|
||||
#endif
|
||||
|
||||
.extern OPENSSL_armcap_P
|
||||
.hidden OPENSSL_armcap_P
|
||||
___
|
||||
|
||||
print $code;
|
||||
close STDOUT or die "error closing STDOUT: $!";
|
||||
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
#include "asn1_local.h"
|
||||
|
||||
int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len)
|
||||
{
|
||||
return ASN1_STRING_set(x, d, len);
|
||||
}
|
||||
|
||||
int ossl_i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp)
|
||||
{
|
||||
int ret, j, bits, len;
|
||||
unsigned char *p, *d;
|
||||
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
|
||||
len = a->length;
|
||||
|
||||
if (len > 0) {
|
||||
if (a->flags & ASN1_STRING_FLAG_BITS_LEFT) {
|
||||
bits = (int)a->flags & 0x07;
|
||||
} else {
|
||||
for (; len > 0; len--) {
|
||||
if (a->data[len - 1])
|
||||
break;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
bits = 0;
|
||||
} else {
|
||||
j = a->data[len - 1];
|
||||
if (j & 0x01)
|
||||
bits = 0;
|
||||
else if (j & 0x02)
|
||||
bits = 1;
|
||||
else if (j & 0x04)
|
||||
bits = 2;
|
||||
else if (j & 0x08)
|
||||
bits = 3;
|
||||
else if (j & 0x10)
|
||||
bits = 4;
|
||||
else if (j & 0x20)
|
||||
bits = 5;
|
||||
else if (j & 0x40)
|
||||
bits = 6;
|
||||
else if (j & 0x80)
|
||||
bits = 7;
|
||||
else
|
||||
bits = 0; /* should not happen */
|
||||
}
|
||||
}
|
||||
} else
|
||||
bits = 0;
|
||||
|
||||
ret = 1 + len;
|
||||
if (pp == NULL)
|
||||
return ret;
|
||||
|
||||
p = *pp;
|
||||
|
||||
*(p++) = (unsigned char)bits;
|
||||
d = a->data;
|
||||
if (len > 0) {
|
||||
memcpy(p, d, len);
|
||||
p += len;
|
||||
p[-1] &= (0xff << bits);
|
||||
}
|
||||
*pp = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ASN1_BIT_STRING *ossl_c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
|
||||
const unsigned char **pp, long len)
|
||||
{
|
||||
ASN1_BIT_STRING *ret = NULL;
|
||||
const unsigned char *p;
|
||||
unsigned char *s;
|
||||
int i = 0;
|
||||
|
||||
if (len < 1) {
|
||||
i = ASN1_R_STRING_TOO_SHORT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (len > INT_MAX) {
|
||||
i = ASN1_R_STRING_TOO_LONG;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
if ((ret = ASN1_BIT_STRING_new()) == NULL)
|
||||
return NULL;
|
||||
} else
|
||||
ret = (*a);
|
||||
|
||||
p = *pp;
|
||||
i = *(p++);
|
||||
if (i > 7) {
|
||||
i = ASN1_R_INVALID_BIT_STRING_BITS_LEFT;
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
* We do this to preserve the settings. If we modify the settings, via
|
||||
* the _set_bit function, we will recalculate on output
|
||||
*/
|
||||
ossl_asn1_string_set_bits_left(ret, i);
|
||||
|
||||
if (len-- > 1) { /* using one because of the bits left byte */
|
||||
s = OPENSSL_malloc((int)len);
|
||||
if (s == NULL) {
|
||||
goto err;
|
||||
}
|
||||
memcpy(s, p, (int)len);
|
||||
s[len - 1] &= (0xff << i);
|
||||
p += len;
|
||||
} else
|
||||
s = NULL;
|
||||
|
||||
ASN1_STRING_set0(ret, s, (int)len);
|
||||
ret->type = V_ASN1_BIT_STRING;
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
*pp = p;
|
||||
return ret;
|
||||
err:
|
||||
if (i != 0)
|
||||
ERR_raise(ERR_LIB_ASN1, i);
|
||||
if ((a == NULL) || (*a != ret))
|
||||
ASN1_BIT_STRING_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* These next 2 functions from Goetz Babin-Ebell.
|
||||
*/
|
||||
int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value)
|
||||
{
|
||||
int w, v, iv;
|
||||
unsigned char *c;
|
||||
|
||||
if (n < 0)
|
||||
return 0;
|
||||
|
||||
w = n / 8;
|
||||
v = 1 << (7 - (n & 0x07));
|
||||
iv = ~v;
|
||||
if (!value)
|
||||
v = 0;
|
||||
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
|
||||
a->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); /* clear, set on write */
|
||||
|
||||
if ((a->length < (w + 1)) || (a->data == NULL)) {
|
||||
if (!value)
|
||||
return 1; /* Don't need to set */
|
||||
c = OPENSSL_clear_realloc(a->data, a->length, w + 1);
|
||||
if (c == NULL)
|
||||
return 0;
|
||||
if (w + 1 - a->length > 0)
|
||||
memset(c + a->length, 0, w + 1 - a->length);
|
||||
a->data = c;
|
||||
a->length = w + 1;
|
||||
}
|
||||
a->data[w] = ((a->data[w]) & iv) | v;
|
||||
while ((a->length > 0) && (a->data[a->length - 1] == 0))
|
||||
a->length--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ASN1_BIT_STRING_get_bit(const ASN1_BIT_STRING *a, int n)
|
||||
{
|
||||
int w, v;
|
||||
|
||||
if (n < 0)
|
||||
return 0;
|
||||
|
||||
w = n / 8;
|
||||
v = 1 << (7 - (n & 0x07));
|
||||
if ((a == NULL) || (a->length < (w + 1)) || (a->data == NULL))
|
||||
return 0;
|
||||
return ((a->data[w] & v) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the given bit string contains only bits specified by
|
||||
* the flags vector. Returns 0 if there is at least one bit set in 'a'
|
||||
* which is not specified in 'flags', 1 otherwise.
|
||||
* 'len' is the length of 'flags'.
|
||||
*/
|
||||
int ASN1_BIT_STRING_check(const ASN1_BIT_STRING *a,
|
||||
const unsigned char *flags, int flags_len)
|
||||
{
|
||||
int i, ok;
|
||||
/* Check if there is one bit set at all. */
|
||||
if (!a || !a->data)
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* Check each byte of the internal representation of the bit string.
|
||||
*/
|
||||
ok = 1;
|
||||
for (i = 0; i < a->length && ok; ++i) {
|
||||
unsigned char mask = i < flags_len ? ~flags[i] : 0xff;
|
||||
/* We are done if there is an unneeded bit set. */
|
||||
ok = (a->data[i] & mask) == 0;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/numbers.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include "internal/asn1.h"
|
||||
#include "crypto/asn1.h"
|
||||
|
||||
#ifndef NO_OLD_ASN1
|
||||
# ifndef OPENSSL_NO_STDIO
|
||||
|
||||
void *ASN1_d2i_fp(void *(*xnew) (void), d2i_of_void *d2i, FILE *in, void **x)
|
||||
{
|
||||
BIO *b;
|
||||
void *ret;
|
||||
|
||||
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB);
|
||||
return NULL;
|
||||
}
|
||||
BIO_set_fp(b, in, BIO_NOCLOSE);
|
||||
ret = ASN1_d2i_bio(xnew, d2i, b, x);
|
||||
BIO_free(b);
|
||||
return ret;
|
||||
}
|
||||
# endif
|
||||
|
||||
void *ASN1_d2i_bio(void *(*xnew) (void), d2i_of_void *d2i, BIO *in, void **x)
|
||||
{
|
||||
BUF_MEM *b = NULL;
|
||||
const unsigned char *p;
|
||||
void *ret = NULL;
|
||||
int len;
|
||||
|
||||
len = asn1_d2i_read_bio(in, &b);
|
||||
if (len < 0)
|
||||
goto err;
|
||||
|
||||
p = (unsigned char *)b->data;
|
||||
ret = d2i(x, &p, len);
|
||||
err:
|
||||
BUF_MEM_free(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void *ASN1_item_d2i_bio_ex(const ASN1_ITEM *it, BIO *in, void *x,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
BUF_MEM *b = NULL;
|
||||
const unsigned char *p;
|
||||
void *ret = NULL;
|
||||
int len;
|
||||
|
||||
if (in == NULL)
|
||||
return NULL;
|
||||
len = asn1_d2i_read_bio(in, &b);
|
||||
if (len < 0)
|
||||
goto err;
|
||||
|
||||
p = (const unsigned char *)b->data;
|
||||
ret = ASN1_item_d2i_ex(x, &p, len, it, libctx, propq);
|
||||
err:
|
||||
BUF_MEM_free(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x)
|
||||
{
|
||||
return ASN1_item_d2i_bio_ex(it, in, x, NULL, NULL);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_STDIO
|
||||
void *ASN1_item_d2i_fp_ex(const ASN1_ITEM *it, FILE *in, void *x,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
BIO *b;
|
||||
char *ret;
|
||||
|
||||
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB);
|
||||
return NULL;
|
||||
}
|
||||
BIO_set_fp(b, in, BIO_NOCLOSE);
|
||||
ret = ASN1_item_d2i_bio_ex(it, b, x, libctx, propq);
|
||||
BIO_free(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x)
|
||||
{
|
||||
return ASN1_item_d2i_fp_ex(it, in, x, NULL, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define HEADER_SIZE 8
|
||||
#define ASN1_CHUNK_INITIAL_SIZE (16 * 1024)
|
||||
int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb)
|
||||
{
|
||||
BUF_MEM *b;
|
||||
unsigned char *p;
|
||||
int i;
|
||||
size_t want = HEADER_SIZE;
|
||||
uint32_t eos = 0;
|
||||
size_t off = 0;
|
||||
size_t len = 0;
|
||||
size_t diff;
|
||||
|
||||
const unsigned char *q;
|
||||
long slen;
|
||||
int inf, tag, xclass;
|
||||
|
||||
b = BUF_MEM_new();
|
||||
if (b == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ERR_set_mark();
|
||||
for (;;) {
|
||||
diff = len - off;
|
||||
if (want >= diff) {
|
||||
want -= diff;
|
||||
|
||||
if (len + want < len || !BUF_MEM_grow_clean(b, len + want)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB);
|
||||
goto err;
|
||||
}
|
||||
i = BIO_read(in, &(b->data[len]), want);
|
||||
if (i < 0 && diff == 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA);
|
||||
goto err;
|
||||
}
|
||||
if (i > 0) {
|
||||
if (len + i < len) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
len += i;
|
||||
if ((size_t)i < want)
|
||||
continue;
|
||||
|
||||
}
|
||||
}
|
||||
/* else data already loaded */
|
||||
|
||||
p = (unsigned char *)&(b->data[off]);
|
||||
q = p;
|
||||
diff = len - off;
|
||||
if (diff == 0)
|
||||
goto err;
|
||||
inf = ASN1_get_object(&q, &slen, &tag, &xclass, diff);
|
||||
if (inf & 0x80) {
|
||||
unsigned long e;
|
||||
|
||||
e = ERR_GET_REASON(ERR_peek_last_error());
|
||||
if (e != ASN1_R_TOO_LONG)
|
||||
goto err;
|
||||
ERR_pop_to_mark();
|
||||
}
|
||||
i = q - p; /* header length */
|
||||
off += i; /* end of data */
|
||||
|
||||
if (inf & 1) {
|
||||
/* no data body so go round again */
|
||||
if (eos == UINT32_MAX) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
eos++;
|
||||
want = HEADER_SIZE;
|
||||
} else if (eos && (slen == 0) && (tag == V_ASN1_EOC)) {
|
||||
/* eos value, so go back and read another header */
|
||||
eos--;
|
||||
if (eos == 0)
|
||||
break;
|
||||
else
|
||||
want = HEADER_SIZE;
|
||||
} else {
|
||||
/* suck in slen bytes of data */
|
||||
want = slen;
|
||||
if (want > (len - off)) {
|
||||
size_t chunk_max = ASN1_CHUNK_INITIAL_SIZE;
|
||||
|
||||
want -= (len - off);
|
||||
if (want > INT_MAX /* BIO_read takes an int length */ ||
|
||||
len + want < len) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
while (want > 0) {
|
||||
/*
|
||||
* Read content in chunks of increasing size
|
||||
* so we can return an error for EOF without
|
||||
* having to allocate the entire content length
|
||||
* in one go.
|
||||
*/
|
||||
size_t chunk = want > chunk_max ? chunk_max : want;
|
||||
|
||||
if (!BUF_MEM_grow_clean(b, len + chunk)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB);
|
||||
goto err;
|
||||
}
|
||||
want -= chunk;
|
||||
while (chunk > 0) {
|
||||
i = BIO_read(in, &(b->data[len]), chunk);
|
||||
if (i <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ENOUGH_DATA);
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
* This can't overflow because |len+want| didn't
|
||||
* overflow.
|
||||
*/
|
||||
len += i;
|
||||
chunk -= i;
|
||||
}
|
||||
if (chunk_max < INT_MAX/2)
|
||||
chunk_max *= 2;
|
||||
}
|
||||
}
|
||||
if (off + slen < off) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
off += slen;
|
||||
if (eos == 0) {
|
||||
break;
|
||||
} else
|
||||
want = HEADER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
if (off > INT_MAX) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG);
|
||||
goto err;
|
||||
}
|
||||
|
||||
*pb = b;
|
||||
return off;
|
||||
err:
|
||||
ERR_clear_last_mark();
|
||||
BUF_MEM_free(b);
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* We need to use some engine deprecated APIs */
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#include <openssl/engine.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/x509.h"
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
|
||||
int ASN1_digest(i2d_of_void *i2d, const EVP_MD *type, char *data,
|
||||
unsigned char *md, unsigned int *len)
|
||||
{
|
||||
int inl;
|
||||
unsigned char *str, *p;
|
||||
|
||||
inl = i2d(data, NULL);
|
||||
if (inl <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
if ((str = OPENSSL_malloc(inl)) == NULL)
|
||||
return 0;
|
||||
p = str;
|
||||
i2d(data, &p);
|
||||
|
||||
if (!EVP_Digest(str, inl, md, len, type, NULL)) {
|
||||
OPENSSL_free(str);
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_free(str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int ossl_asn1_item_digest_ex(const ASN1_ITEM *it, const EVP_MD *md, void *asn,
|
||||
unsigned char *data, unsigned int *len,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
int i, ret = 0;
|
||||
unsigned char *str = NULL;
|
||||
EVP_MD *fetched_md = (EVP_MD *)md;
|
||||
|
||||
i = ASN1_item_i2d(asn, &str, it);
|
||||
if (i < 0 || str == NULL)
|
||||
return 0;
|
||||
|
||||
if (EVP_MD_get0_provider(md) == NULL) {
|
||||
#if !defined(OPENSSL_NO_ENGINE)
|
||||
ENGINE *tmpeng = ENGINE_get_digest_engine(EVP_MD_get_type(md));
|
||||
|
||||
if (tmpeng != NULL)
|
||||
ENGINE_finish(tmpeng);
|
||||
else
|
||||
#endif
|
||||
fetched_md = EVP_MD_fetch(libctx, EVP_MD_get0_name(md), propq);
|
||||
}
|
||||
if (fetched_md == NULL)
|
||||
goto err;
|
||||
|
||||
ret = EVP_Digest(str, i, data, len, fetched_md, NULL);
|
||||
err:
|
||||
OPENSSL_free(str);
|
||||
if (fetched_md != md)
|
||||
EVP_MD_free(fetched_md);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ASN1_item_digest(const ASN1_ITEM *it, const EVP_MD *md, void *asn,
|
||||
unsigned char *data, unsigned int *len)
|
||||
{
|
||||
return ossl_asn1_item_digest_ex(it, md, asn, data, len, NULL, NULL);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1t.h>
|
||||
|
||||
#ifndef NO_OLD_ASN1
|
||||
|
||||
void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, const void *x)
|
||||
{
|
||||
unsigned char *b, *p;
|
||||
const unsigned char *p2;
|
||||
int i;
|
||||
char *ret;
|
||||
|
||||
if (x == NULL)
|
||||
return NULL;
|
||||
|
||||
i = i2d(x, NULL);
|
||||
if (i <= 0)
|
||||
return NULL;
|
||||
|
||||
b = OPENSSL_malloc(i + 10);
|
||||
if (b == NULL)
|
||||
return NULL;
|
||||
p = b;
|
||||
i = i2d(x, &p);
|
||||
p2 = b;
|
||||
ret = d2i(NULL, &p2, i);
|
||||
OPENSSL_free(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ASN1_ITEM version of dup: this follows the model above except we don't
|
||||
* need to allocate the buffer. At some point this could be rewritten to
|
||||
* directly dup the underlying structure instead of doing and encode and
|
||||
* decode.
|
||||
*/
|
||||
|
||||
void *ASN1_item_dup(const ASN1_ITEM *it, const void *x)
|
||||
{
|
||||
ASN1_aux_cb *asn1_cb = NULL;
|
||||
unsigned char *b = NULL;
|
||||
const unsigned char *p;
|
||||
long i;
|
||||
ASN1_VALUE *ret;
|
||||
OSSL_LIB_CTX *libctx = NULL;
|
||||
const char *propq = NULL;
|
||||
|
||||
if (x == NULL)
|
||||
return NULL;
|
||||
|
||||
if (it->itype == ASN1_ITYPE_SEQUENCE || it->itype == ASN1_ITYPE_CHOICE
|
||||
|| it->itype == ASN1_ITYPE_NDEF_SEQUENCE) {
|
||||
const ASN1_AUX *aux = it->funcs;
|
||||
|
||||
asn1_cb = aux != NULL ? aux->asn1_cb : NULL;
|
||||
}
|
||||
|
||||
if (asn1_cb != NULL) {
|
||||
if (!asn1_cb(ASN1_OP_DUP_PRE, (ASN1_VALUE **)&x, it, NULL)
|
||||
|| !asn1_cb(ASN1_OP_GET0_LIBCTX, (ASN1_VALUE **)&x, it, &libctx)
|
||||
|| !asn1_cb(ASN1_OP_GET0_PROPQ, (ASN1_VALUE **)&x, it, &propq))
|
||||
goto auxerr;
|
||||
}
|
||||
|
||||
i = ASN1_item_i2d(x, &b, it);
|
||||
if (i < 0 || b == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
return NULL;
|
||||
}
|
||||
p = b;
|
||||
ret = ASN1_item_d2i_ex(NULL, &p, i, it, libctx, propq);
|
||||
OPENSSL_free(b);
|
||||
|
||||
if (asn1_cb != NULL
|
||||
&& !asn1_cb(ASN1_OP_DUP_POST, &ret, it, (void *)x))
|
||||
goto auxerr;
|
||||
|
||||
return ret;
|
||||
|
||||
auxerr:
|
||||
ERR_raise_data(ERR_LIB_ASN1, ASN1_R_AUX_ERROR, "Type=%s", it->sname);
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* GENERALIZEDTIME implementation. Based on UTCTIME
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
#include "asn1_local.h"
|
||||
#include <openssl/asn1t.h>
|
||||
|
||||
IMPLEMENT_ASN1_DUP_FUNCTION(ASN1_GENERALIZEDTIME)
|
||||
|
||||
/* This is the primary function used to parse ASN1_GENERALIZEDTIME */
|
||||
static int asn1_generalizedtime_to_tm(struct tm *tm,
|
||||
const ASN1_GENERALIZEDTIME *d)
|
||||
{
|
||||
/* wrapper around ossl_asn1_time_to_tm */
|
||||
if (d->type != V_ASN1_GENERALIZEDTIME)
|
||||
return 0;
|
||||
return ossl_asn1_time_to_tm(tm, d);
|
||||
}
|
||||
|
||||
int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d)
|
||||
{
|
||||
return asn1_generalizedtime_to_tm(NULL, d);
|
||||
}
|
||||
|
||||
int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str)
|
||||
{
|
||||
ASN1_GENERALIZEDTIME t;
|
||||
|
||||
t.type = V_ASN1_GENERALIZEDTIME;
|
||||
t.length = strlen(str);
|
||||
t.data = (unsigned char *)str;
|
||||
t.flags = 0;
|
||||
|
||||
if (!ASN1_GENERALIZEDTIME_check(&t))
|
||||
return 0;
|
||||
|
||||
if (s != NULL && !ASN1_STRING_copy(s, &t))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,
|
||||
time_t t)
|
||||
{
|
||||
return ASN1_GENERALIZEDTIME_adj(s, t, 0, 0);
|
||||
}
|
||||
|
||||
ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
|
||||
time_t t, int offset_day,
|
||||
long offset_sec)
|
||||
{
|
||||
struct tm *ts;
|
||||
struct tm data;
|
||||
|
||||
ts = OPENSSL_gmtime(&t, &data);
|
||||
if (ts == NULL)
|
||||
return NULL;
|
||||
|
||||
if (offset_day || offset_sec) {
|
||||
if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ossl_asn1_time_from_tm(s, ts, V_ASN1_GENERALIZEDTIME);
|
||||
}
|
||||
|
||||
int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm)
|
||||
{
|
||||
if (tm->type != V_ASN1_GENERALIZEDTIME)
|
||||
return 0;
|
||||
return ASN1_TIME_print(bp, tm);
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#ifndef NO_OLD_ASN1
|
||||
|
||||
# ifndef OPENSSL_NO_STDIO
|
||||
int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, const void *x)
|
||||
{
|
||||
BIO *b;
|
||||
int ret;
|
||||
|
||||
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB);
|
||||
return 0;
|
||||
}
|
||||
BIO_set_fp(b, out, BIO_NOCLOSE);
|
||||
ret = ASN1_i2d_bio(i2d, b, x);
|
||||
BIO_free(b);
|
||||
return ret;
|
||||
}
|
||||
# endif
|
||||
|
||||
int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, const void *x)
|
||||
{
|
||||
char *b;
|
||||
unsigned char *p;
|
||||
int i, j = 0, n, ret = 1;
|
||||
|
||||
n = i2d(x, NULL);
|
||||
if (n <= 0)
|
||||
return 0;
|
||||
|
||||
b = OPENSSL_malloc(n);
|
||||
if (b == NULL)
|
||||
return 0;
|
||||
|
||||
p = (unsigned char *)b;
|
||||
i2d(x, &p);
|
||||
|
||||
for (;;) {
|
||||
i = BIO_write(out, &(b[j]), n);
|
||||
if (i == n)
|
||||
break;
|
||||
if (i <= 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
j += i;
|
||||
n -= i;
|
||||
}
|
||||
OPENSSL_free(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_STDIO
|
||||
int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, const void *x)
|
||||
{
|
||||
BIO *b;
|
||||
int ret;
|
||||
|
||||
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_BUF_LIB);
|
||||
return 0;
|
||||
}
|
||||
BIO_set_fp(b, out, BIO_NOCLOSE);
|
||||
ret = ASN1_item_i2d_bio(it, b, x);
|
||||
BIO_free(b);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, const void *x)
|
||||
{
|
||||
unsigned char *b = NULL;
|
||||
int i, j = 0, n, ret = 1;
|
||||
|
||||
n = ASN1_item_i2d(x, &b, it);
|
||||
if (n < 0 || b == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
i = BIO_write(out, &(b[j]), n);
|
||||
if (i == n)
|
||||
break;
|
||||
if (i <= 0) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
j += i;
|
||||
n -= i;
|
||||
}
|
||||
OPENSSL_free(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
BIO *ASN1_item_i2d_mem_bio(const ASN1_ITEM *it, const ASN1_VALUE *val)
|
||||
{
|
||||
BIO *res;
|
||||
|
||||
if (it == NULL || val == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((res = BIO_new(BIO_s_mem())) == NULL)
|
||||
return NULL;
|
||||
if (ASN1_item_i2d_bio(it, res, val) <= 0) {
|
||||
BIO_free(res);
|
||||
res = NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/numbers.h"
|
||||
#include <limits.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bn.h>
|
||||
#include "asn1_local.h"
|
||||
|
||||
ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x)
|
||||
{
|
||||
return ASN1_STRING_dup(x);
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y)
|
||||
{
|
||||
int neg, ret;
|
||||
/* Compare signs */
|
||||
neg = x->type & V_ASN1_NEG;
|
||||
if (neg != (y->type & V_ASN1_NEG)) {
|
||||
if (neg)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = ASN1_STRING_cmp(x, y);
|
||||
|
||||
if (neg)
|
||||
return -ret;
|
||||
else
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This converts a big endian buffer and sign into its content encoding.
|
||||
* This is used for INTEGER and ENUMERATED types.
|
||||
* The internal representation is an ASN1_STRING whose data is a big endian
|
||||
* representation of the value, ignoring the sign. The sign is determined by
|
||||
* the type: if type & V_ASN1_NEG is true it is negative, otherwise positive.
|
||||
*
|
||||
* Positive integers are no problem: they are almost the same as the DER
|
||||
* encoding, except if the first byte is >= 0x80 we need to add a zero pad.
|
||||
*
|
||||
* Negative integers are a bit trickier...
|
||||
* The DER representation of negative integers is in 2s complement form.
|
||||
* The internal form is converted by complementing each octet and finally
|
||||
* adding one to the result. This can be done less messily with a little trick.
|
||||
* If the internal form has trailing zeroes then they will become FF by the
|
||||
* complement and 0 by the add one (due to carry) so just copy as many trailing
|
||||
* zeros to the destination as there are in the source. The carry will add one
|
||||
* to the last none zero octet: so complement this octet and add one and finally
|
||||
* complement any left over until you get to the start of the string.
|
||||
*
|
||||
* Padding is a little trickier too. If the first bytes is > 0x80 then we pad
|
||||
* with 0xff. However if the first byte is 0x80 and one of the following bytes
|
||||
* is non-zero we pad with 0xff. The reason for this distinction is that 0x80
|
||||
* followed by optional zeros isn't padded.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If |pad| is zero, the operation is effectively reduced to memcpy,
|
||||
* and if |pad| is 0xff, then it performs two's complement, ~dst + 1.
|
||||
* Note that in latter case sequence of zeros yields itself, and so
|
||||
* does 0x80 followed by any number of zeros. These properties are
|
||||
* used elsewhere below...
|
||||
*/
|
||||
static void twos_complement(unsigned char *dst, const unsigned char *src,
|
||||
size_t len, unsigned char pad)
|
||||
{
|
||||
unsigned int carry = pad & 1;
|
||||
|
||||
/* Begin at the end of the encoding */
|
||||
if (len != 0) {
|
||||
/*
|
||||
* if len == 0 then src/dst could be NULL, and this would be undefined
|
||||
* behaviour.
|
||||
*/
|
||||
dst += len;
|
||||
src += len;
|
||||
}
|
||||
/* two's complement value: ~value + 1 */
|
||||
while (len-- != 0) {
|
||||
*(--dst) = (unsigned char)(carry += *(--src) ^ pad);
|
||||
carry >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t i2c_ibuf(const unsigned char *b, size_t blen, int neg,
|
||||
unsigned char **pp)
|
||||
{
|
||||
unsigned int pad = 0;
|
||||
size_t ret, i;
|
||||
unsigned char *p, pb = 0;
|
||||
|
||||
if (b != NULL && blen) {
|
||||
ret = blen;
|
||||
i = b[0];
|
||||
if (!neg && (i > 127)) {
|
||||
pad = 1;
|
||||
pb = 0;
|
||||
} else if (neg) {
|
||||
pb = 0xFF;
|
||||
if (i > 128) {
|
||||
pad = 1;
|
||||
} else if (i == 128) {
|
||||
/*
|
||||
* Special case [of minimal negative for given length]:
|
||||
* if any other bytes non zero we pad, otherwise we don't.
|
||||
*/
|
||||
for (pad = 0, i = 1; i < blen; i++)
|
||||
pad |= b[i];
|
||||
pb = pad != 0 ? 0xffU : 0;
|
||||
pad = pb & 1;
|
||||
}
|
||||
}
|
||||
ret += pad;
|
||||
} else {
|
||||
ret = 1;
|
||||
blen = 0; /* reduce '(b == NULL || blen == 0)' to '(blen == 0)' */
|
||||
}
|
||||
|
||||
if (pp == NULL || (p = *pp) == NULL)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* This magically handles all corner cases, such as '(b == NULL ||
|
||||
* blen == 0)', non-negative value, "negative" zero, 0x80 followed
|
||||
* by any number of zeros...
|
||||
*/
|
||||
*p = pb;
|
||||
p += pad; /* yes, p[0] can be written twice, but it's little
|
||||
* price to pay for eliminated branches */
|
||||
twos_complement(p, b, blen, pb);
|
||||
|
||||
*pp += ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* convert content octets into a big endian buffer. Returns the length
|
||||
* of buffer or 0 on error: for malformed INTEGER. If output buffer is
|
||||
* NULL just return length.
|
||||
*/
|
||||
|
||||
static size_t c2i_ibuf(unsigned char *b, int *pneg,
|
||||
const unsigned char *p, size_t plen)
|
||||
{
|
||||
int neg, pad;
|
||||
/* Zero content length is illegal */
|
||||
if (plen == 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_ZERO_CONTENT);
|
||||
return 0;
|
||||
}
|
||||
neg = p[0] & 0x80;
|
||||
if (pneg)
|
||||
*pneg = neg;
|
||||
/* Handle common case where length is 1 octet separately */
|
||||
if (plen == 1) {
|
||||
if (b != NULL) {
|
||||
if (neg)
|
||||
b[0] = (p[0] ^ 0xFF) + 1;
|
||||
else
|
||||
b[0] = p[0];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
pad = 0;
|
||||
if (p[0] == 0) {
|
||||
pad = 1;
|
||||
} else if (p[0] == 0xFF) {
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* Special case [of "one less minimal negative" for given length]:
|
||||
* if any other bytes non zero it was padded, otherwise not.
|
||||
*/
|
||||
for (pad = 0, i = 1; i < plen; i++)
|
||||
pad |= p[i];
|
||||
pad = pad != 0 ? 1 : 0;
|
||||
}
|
||||
/* reject illegal padding: first two octets MSB can't match */
|
||||
if (pad && (neg == (p[1] & 0x80))) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_PADDING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* skip over pad */
|
||||
p += pad;
|
||||
plen -= pad;
|
||||
|
||||
if (b != NULL)
|
||||
twos_complement(b, p, plen, neg ? 0xffU : 0);
|
||||
|
||||
return plen;
|
||||
}
|
||||
|
||||
int ossl_i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp)
|
||||
{
|
||||
return i2c_ibuf(a->data, a->length, a->type & V_ASN1_NEG, pp);
|
||||
}
|
||||
|
||||
/* Convert big endian buffer into uint64_t, return 0 on error */
|
||||
static int asn1_get_uint64(uint64_t *pr, const unsigned char *b, size_t blen)
|
||||
{
|
||||
size_t i;
|
||||
uint64_t r;
|
||||
|
||||
if (blen > sizeof(*pr)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
if (b == NULL)
|
||||
return 0;
|
||||
for (r = 0, i = 0; i < blen; i++) {
|
||||
r <<= 8;
|
||||
r |= b[i];
|
||||
}
|
||||
*pr = r;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write uint64_t to big endian buffer and return offset to first
|
||||
* written octet. In other words it returns offset in range from 0
|
||||
* to 7, with 0 denoting 8 written octets and 7 - one.
|
||||
*/
|
||||
static size_t asn1_put_uint64(unsigned char b[sizeof(uint64_t)], uint64_t r)
|
||||
{
|
||||
size_t off = sizeof(uint64_t);
|
||||
|
||||
do {
|
||||
b[--off] = (unsigned char)r;
|
||||
} while (r >>= 8);
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/*
|
||||
* Absolute value of INT64_MIN: we can't just use -INT64_MIN as gcc produces
|
||||
* overflow warnings.
|
||||
*/
|
||||
#define ABS_INT64_MIN ((uint64_t)INT64_MAX + (-(INT64_MIN + INT64_MAX)))
|
||||
|
||||
/* signed version of asn1_get_uint64 */
|
||||
static int asn1_get_int64(int64_t *pr, const unsigned char *b, size_t blen,
|
||||
int neg)
|
||||
{
|
||||
uint64_t r;
|
||||
if (asn1_get_uint64(&r, b, blen) == 0)
|
||||
return 0;
|
||||
if (neg) {
|
||||
if (r <= INT64_MAX) {
|
||||
/*
|
||||
* Most significant bit is guaranteed to be clear, negation
|
||||
* is guaranteed to be meaningful in platform-neutral sense.
|
||||
*/
|
||||
*pr = -(int64_t)r;
|
||||
} else if (r == ABS_INT64_MIN) {
|
||||
/*
|
||||
* This never happens if INT64_MAX == ABS_INT64_MIN, e.g.
|
||||
* on ones'-complement system.
|
||||
*/
|
||||
*pr = (int64_t)(0 - r);
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (r <= INT64_MAX) {
|
||||
*pr = (int64_t)r;
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Convert ASN1 INTEGER content octets to ASN1_INTEGER structure */
|
||||
ASN1_INTEGER *ossl_c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
|
||||
long len)
|
||||
{
|
||||
ASN1_INTEGER *ret = NULL;
|
||||
size_t r;
|
||||
int neg;
|
||||
|
||||
r = c2i_ibuf(NULL, NULL, *pp, len);
|
||||
|
||||
if (r == 0)
|
||||
return NULL;
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
ret = ASN1_INTEGER_new();
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
ret->type = V_ASN1_INTEGER;
|
||||
} else
|
||||
ret = *a;
|
||||
|
||||
if (ASN1_STRING_set(ret, NULL, r) == 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
c2i_ibuf(ret->data, &neg, *pp, len);
|
||||
|
||||
if (neg != 0)
|
||||
ret->type |= V_ASN1_NEG;
|
||||
else
|
||||
ret->type &= ~V_ASN1_NEG;
|
||||
|
||||
*pp += len;
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
return ret;
|
||||
err:
|
||||
if (a == NULL || *a != ret)
|
||||
ASN1_INTEGER_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int asn1_string_get_int64(int64_t *pr, const ASN1_STRING *a, int itype)
|
||||
{
|
||||
if (a == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
if ((a->type & ~V_ASN1_NEG) != itype) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_WRONG_INTEGER_TYPE);
|
||||
return 0;
|
||||
}
|
||||
return asn1_get_int64(pr, a->data, a->length, a->type & V_ASN1_NEG);
|
||||
}
|
||||
|
||||
static int asn1_string_set_int64(ASN1_STRING *a, int64_t r, int itype)
|
||||
{
|
||||
unsigned char tbuf[sizeof(r)];
|
||||
size_t off;
|
||||
|
||||
a->type = itype;
|
||||
if (r < 0) {
|
||||
/*
|
||||
* Most obvious '-r' triggers undefined behaviour for most
|
||||
* common INT64_MIN. Even though below '0 - (uint64_t)r' can
|
||||
* appear two's-complement centric, it does produce correct/
|
||||
* expected result even on ones' complement. This is because
|
||||
* cast to unsigned has to change bit pattern...
|
||||
*/
|
||||
off = asn1_put_uint64(tbuf, 0 - (uint64_t)r);
|
||||
a->type |= V_ASN1_NEG;
|
||||
} else {
|
||||
off = asn1_put_uint64(tbuf, r);
|
||||
a->type &= ~V_ASN1_NEG;
|
||||
}
|
||||
return ASN1_STRING_set(a, tbuf + off, sizeof(tbuf) - off);
|
||||
}
|
||||
|
||||
static int asn1_string_get_uint64(uint64_t *pr, const ASN1_STRING *a,
|
||||
int itype)
|
||||
{
|
||||
if (a == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
if ((a->type & ~V_ASN1_NEG) != itype) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_WRONG_INTEGER_TYPE);
|
||||
return 0;
|
||||
}
|
||||
if (a->type & V_ASN1_NEG) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_NEGATIVE_VALUE);
|
||||
return 0;
|
||||
}
|
||||
return asn1_get_uint64(pr, a->data, a->length);
|
||||
}
|
||||
|
||||
static int asn1_string_set_uint64(ASN1_STRING *a, uint64_t r, int itype)
|
||||
{
|
||||
unsigned char tbuf[sizeof(r)];
|
||||
size_t off;
|
||||
|
||||
a->type = itype;
|
||||
off = asn1_put_uint64(tbuf, r);
|
||||
return ASN1_STRING_set(a, tbuf + off, sizeof(tbuf) - off);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a version of d2i_ASN1_INTEGER that ignores the sign bit of ASN1
|
||||
* integers: some broken software can encode a positive INTEGER with its MSB
|
||||
* set as negative (it doesn't add a padding zero).
|
||||
*/
|
||||
|
||||
ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
ASN1_INTEGER *ret = NULL;
|
||||
const unsigned char *p;
|
||||
unsigned char *s;
|
||||
long len = 0;
|
||||
int inf, tag, xclass;
|
||||
int i = 0;
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL)) {
|
||||
if ((ret = ASN1_INTEGER_new()) == NULL)
|
||||
return NULL;
|
||||
ret->type = V_ASN1_INTEGER;
|
||||
} else
|
||||
ret = (*a);
|
||||
|
||||
p = *pp;
|
||||
inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
|
||||
if (inf & 0x80) {
|
||||
i = ASN1_R_BAD_OBJECT_HEADER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (tag != V_ASN1_INTEGER) {
|
||||
i = ASN1_R_EXPECTING_AN_INTEGER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (len < 0) {
|
||||
i = ASN1_R_ILLEGAL_NEGATIVE_VALUE;
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it signifies
|
||||
* a missing NULL parameter.
|
||||
*/
|
||||
s = OPENSSL_malloc((int)len + 1);
|
||||
if (s == NULL)
|
||||
goto err;
|
||||
ret->type = V_ASN1_INTEGER;
|
||||
if (len) {
|
||||
if ((*p == 0) && (len != 1)) {
|
||||
p++;
|
||||
len--;
|
||||
}
|
||||
memcpy(s, p, (int)len);
|
||||
p += len;
|
||||
}
|
||||
|
||||
ASN1_STRING_set0(ret, s, (int)len);
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
*pp = p;
|
||||
return ret;
|
||||
err:
|
||||
if (i != 0)
|
||||
ERR_raise(ERR_LIB_ASN1, i);
|
||||
if ((a == NULL) || (*a != ret))
|
||||
ASN1_INTEGER_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static ASN1_STRING *bn_to_asn1_string(const BIGNUM *bn, ASN1_STRING *ai,
|
||||
int atype)
|
||||
{
|
||||
ASN1_INTEGER *ret;
|
||||
int len;
|
||||
|
||||
if (ai == NULL) {
|
||||
ret = ASN1_STRING_type_new(atype);
|
||||
} else {
|
||||
ret = ai;
|
||||
ret->type = atype;
|
||||
}
|
||||
|
||||
if (ret == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_NESTED_ASN1_ERROR);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (BN_is_negative(bn) && !BN_is_zero(bn))
|
||||
ret->type |= V_ASN1_NEG_INTEGER;
|
||||
|
||||
len = BN_num_bytes(bn);
|
||||
|
||||
if (len == 0)
|
||||
len = 1;
|
||||
|
||||
if (ASN1_STRING_set(ret, NULL, len) == 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Correct zero case */
|
||||
if (BN_is_zero(bn))
|
||||
ret->data[0] = 0;
|
||||
else
|
||||
len = BN_bn2bin(bn, ret->data);
|
||||
ret->length = len;
|
||||
return ret;
|
||||
err:
|
||||
if (ret != ai)
|
||||
ASN1_INTEGER_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BIGNUM *asn1_string_to_bn(const ASN1_INTEGER *ai, BIGNUM *bn,
|
||||
int itype)
|
||||
{
|
||||
BIGNUM *ret;
|
||||
|
||||
if ((ai->type & ~V_ASN1_NEG) != itype) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_WRONG_INTEGER_TYPE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = BN_bin2bn(ai->data, ai->length, bn);
|
||||
if (ret == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_BN_LIB);
|
||||
return NULL;
|
||||
}
|
||||
if (ai->type & V_ASN1_NEG)
|
||||
BN_set_negative(ret, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_get_int64(int64_t *pr, const ASN1_INTEGER *a)
|
||||
{
|
||||
return asn1_string_get_int64(pr, a, V_ASN1_INTEGER);
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_set_int64(ASN1_INTEGER *a, int64_t r)
|
||||
{
|
||||
return asn1_string_set_int64(a, r, V_ASN1_INTEGER);
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_get_uint64(uint64_t *pr, const ASN1_INTEGER *a)
|
||||
{
|
||||
return asn1_string_get_uint64(pr, a, V_ASN1_INTEGER);
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_set_uint64(ASN1_INTEGER *a, uint64_t r)
|
||||
{
|
||||
return asn1_string_set_uint64(a, r, V_ASN1_INTEGER);
|
||||
}
|
||||
|
||||
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
|
||||
{
|
||||
return ASN1_INTEGER_set_int64(a, v);
|
||||
}
|
||||
|
||||
long ASN1_INTEGER_get(const ASN1_INTEGER *a)
|
||||
{
|
||||
int i;
|
||||
int64_t r;
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
i = ASN1_INTEGER_get_int64(&r, a);
|
||||
if (i == 0)
|
||||
return -1;
|
||||
if (r > LONG_MAX || r < LONG_MIN)
|
||||
return -1;
|
||||
return (long)r;
|
||||
}
|
||||
|
||||
ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai)
|
||||
{
|
||||
return bn_to_asn1_string(bn, ai, V_ASN1_INTEGER);
|
||||
}
|
||||
|
||||
BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn)
|
||||
{
|
||||
return asn1_string_to_bn(ai, bn, V_ASN1_INTEGER);
|
||||
}
|
||||
|
||||
int ASN1_ENUMERATED_get_int64(int64_t *pr, const ASN1_ENUMERATED *a)
|
||||
{
|
||||
return asn1_string_get_int64(pr, a, V_ASN1_ENUMERATED);
|
||||
}
|
||||
|
||||
int ASN1_ENUMERATED_set_int64(ASN1_ENUMERATED *a, int64_t r)
|
||||
{
|
||||
return asn1_string_set_int64(a, r, V_ASN1_ENUMERATED);
|
||||
}
|
||||
|
||||
int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v)
|
||||
{
|
||||
return ASN1_ENUMERATED_set_int64(a, v);
|
||||
}
|
||||
|
||||
long ASN1_ENUMERATED_get(const ASN1_ENUMERATED *a)
|
||||
{
|
||||
int i;
|
||||
int64_t r;
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
if ((a->type & ~V_ASN1_NEG) != V_ASN1_ENUMERATED)
|
||||
return -1;
|
||||
if (a->length > (int)sizeof(long))
|
||||
return 0xffffffffL;
|
||||
i = ASN1_ENUMERATED_get_int64(&r, a);
|
||||
if (i == 0)
|
||||
return -1;
|
||||
if (r > LONG_MAX || r < LONG_MIN)
|
||||
return -1;
|
||||
return (long)r;
|
||||
}
|
||||
|
||||
ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(const BIGNUM *bn, ASN1_ENUMERATED *ai)
|
||||
{
|
||||
return bn_to_asn1_string(bn, ai, V_ASN1_ENUMERATED);
|
||||
}
|
||||
|
||||
BIGNUM *ASN1_ENUMERATED_to_BN(const ASN1_ENUMERATED *ai, BIGNUM *bn)
|
||||
{
|
||||
return asn1_string_to_bn(ai, bn, V_ASN1_ENUMERATED);
|
||||
}
|
||||
|
||||
/* Internal functions used by x_int64.c */
|
||||
int ossl_c2i_uint64_int(uint64_t *ret, int *neg,
|
||||
const unsigned char **pp, long len)
|
||||
{
|
||||
unsigned char buf[sizeof(uint64_t)];
|
||||
size_t buflen;
|
||||
|
||||
buflen = c2i_ibuf(NULL, NULL, *pp, len);
|
||||
if (buflen == 0)
|
||||
return 0;
|
||||
if (buflen > sizeof(uint64_t)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
(void)c2i_ibuf(buf, neg, *pp, len);
|
||||
return asn1_get_uint64(ret, buf, buflen);
|
||||
}
|
||||
|
||||
int ossl_i2c_uint64_int(unsigned char *p, uint64_t r, int neg)
|
||||
{
|
||||
unsigned char buf[sizeof(uint64_t)];
|
||||
size_t off;
|
||||
|
||||
off = asn1_put_uint64(buf, r);
|
||||
return i2c_ibuf(buf + off, sizeof(buf) - off, neg, &p);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
/*
|
||||
* Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "crypto/ctype.h"
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/unicode.h"
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
static int traverse_string(const unsigned char *p, int len, int inform,
|
||||
int (*rfunc) (unsigned long value, void *in),
|
||||
void *arg);
|
||||
static int in_utf8(unsigned long value, void *arg);
|
||||
static int out_utf8(unsigned long value, void *arg);
|
||||
static int type_str(unsigned long value, void *arg);
|
||||
static int cpy_asc(unsigned long value, void *arg);
|
||||
static int cpy_bmp(unsigned long value, void *arg);
|
||||
static int cpy_univ(unsigned long value, void *arg);
|
||||
static int cpy_utf8(unsigned long value, void *arg);
|
||||
|
||||
/*
|
||||
* These functions take a string in UTF8, ASCII or multibyte form and a mask
|
||||
* of permissible ASN1 string types. It then works out the minimal type
|
||||
* (using the order Numeric < Printable < IA5 < T61 < BMP < Universal < UTF8)
|
||||
* and creates a string of the correct type with the supplied data. Yes this is
|
||||
* horrible: it has to be :-( The 'ncopy' form checks minimum and maximum
|
||||
* size limits too.
|
||||
*/
|
||||
|
||||
int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
|
||||
int inform, unsigned long mask)
|
||||
{
|
||||
return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0);
|
||||
}
|
||||
|
||||
int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
|
||||
int inform, unsigned long mask,
|
||||
long minsize, long maxsize)
|
||||
{
|
||||
int str_type;
|
||||
int ret;
|
||||
char free_out;
|
||||
int outform, outlen = 0;
|
||||
ASN1_STRING *dest;
|
||||
unsigned char *p;
|
||||
int nchar;
|
||||
int (*cpyfunc) (unsigned long, void *) = NULL;
|
||||
if (len == -1)
|
||||
len = strlen((const char *)in);
|
||||
if (!mask)
|
||||
mask = DIRSTRING_TYPE;
|
||||
if (len < 0)
|
||||
return -1;
|
||||
|
||||
/* First do a string check and work out the number of characters */
|
||||
switch (inform) {
|
||||
|
||||
case MBSTRING_BMP:
|
||||
if (len & 1) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH);
|
||||
return -1;
|
||||
}
|
||||
nchar = len >> 1;
|
||||
break;
|
||||
|
||||
case MBSTRING_UNIV:
|
||||
if (len & 3) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
|
||||
return -1;
|
||||
}
|
||||
nchar = len >> 2;
|
||||
break;
|
||||
|
||||
case MBSTRING_UTF8:
|
||||
nchar = 0;
|
||||
/* This counts the characters and does utf8 syntax checking */
|
||||
ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar);
|
||||
if (ret < 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UTF8STRING);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case MBSTRING_ASC:
|
||||
nchar = len;
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((minsize > 0) && (nchar < minsize)) {
|
||||
ERR_raise_data(ERR_LIB_ASN1, ASN1_R_STRING_TOO_SHORT,
|
||||
"minsize=%ld", minsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((maxsize > 0) && (nchar > maxsize)) {
|
||||
ERR_raise_data(ERR_LIB_ASN1, ASN1_R_STRING_TOO_LONG,
|
||||
"maxsize=%ld", maxsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now work out minimal type (if any) */
|
||||
if (traverse_string(in, len, inform, type_str, &mask) < 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_CHARACTERS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now work out output format and string type */
|
||||
outform = MBSTRING_ASC;
|
||||
if (mask & B_ASN1_NUMERICSTRING)
|
||||
str_type = V_ASN1_NUMERICSTRING;
|
||||
else if (mask & B_ASN1_PRINTABLESTRING)
|
||||
str_type = V_ASN1_PRINTABLESTRING;
|
||||
else if (mask & B_ASN1_IA5STRING)
|
||||
str_type = V_ASN1_IA5STRING;
|
||||
else if (mask & B_ASN1_T61STRING)
|
||||
str_type = V_ASN1_T61STRING;
|
||||
else if (mask & B_ASN1_BMPSTRING) {
|
||||
str_type = V_ASN1_BMPSTRING;
|
||||
outform = MBSTRING_BMP;
|
||||
} else if (mask & B_ASN1_UNIVERSALSTRING) {
|
||||
str_type = V_ASN1_UNIVERSALSTRING;
|
||||
outform = MBSTRING_UNIV;
|
||||
} else {
|
||||
str_type = V_ASN1_UTF8STRING;
|
||||
outform = MBSTRING_UTF8;
|
||||
}
|
||||
if (!out)
|
||||
return str_type;
|
||||
if (*out) {
|
||||
free_out = 0;
|
||||
dest = *out;
|
||||
ASN1_STRING_set0(dest, NULL, 0);
|
||||
dest->type = str_type;
|
||||
} else {
|
||||
free_out = 1;
|
||||
dest = ASN1_STRING_type_new(str_type);
|
||||
if (dest == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
return -1;
|
||||
}
|
||||
*out = dest;
|
||||
}
|
||||
/* If both the same type just copy across */
|
||||
if (inform == outform) {
|
||||
if (!ASN1_STRING_set(dest, in, len)) {
|
||||
if (free_out) {
|
||||
ASN1_STRING_free(dest);
|
||||
*out = NULL;
|
||||
}
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
return -1;
|
||||
}
|
||||
return str_type;
|
||||
}
|
||||
|
||||
/* Work out how much space the destination will need */
|
||||
switch (outform) {
|
||||
case MBSTRING_ASC:
|
||||
outlen = nchar;
|
||||
cpyfunc = cpy_asc;
|
||||
break;
|
||||
|
||||
case MBSTRING_BMP:
|
||||
outlen = nchar << 1;
|
||||
cpyfunc = cpy_bmp;
|
||||
break;
|
||||
|
||||
case MBSTRING_UNIV:
|
||||
outlen = nchar << 2;
|
||||
cpyfunc = cpy_univ;
|
||||
break;
|
||||
|
||||
case MBSTRING_UTF8:
|
||||
outlen = 0;
|
||||
traverse_string(in, len, inform, out_utf8, &outlen);
|
||||
cpyfunc = cpy_utf8;
|
||||
break;
|
||||
}
|
||||
if ((p = OPENSSL_malloc(outlen + 1)) == NULL) {
|
||||
if (free_out) {
|
||||
ASN1_STRING_free(dest);
|
||||
*out = NULL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
dest->length = outlen;
|
||||
dest->data = p;
|
||||
p[outlen] = 0;
|
||||
traverse_string(in, len, inform, cpyfunc, &p);
|
||||
return str_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function traverses a string and passes the value of each character to
|
||||
* an optional function along with a void * argument.
|
||||
*/
|
||||
|
||||
static int traverse_string(const unsigned char *p, int len, int inform,
|
||||
int (*rfunc) (unsigned long value, void *in),
|
||||
void *arg)
|
||||
{
|
||||
unsigned long value;
|
||||
int ret;
|
||||
while (len) {
|
||||
if (inform == MBSTRING_ASC) {
|
||||
value = *p++;
|
||||
len--;
|
||||
} else if (inform == MBSTRING_BMP) {
|
||||
value = *p++ << 8;
|
||||
value |= *p++;
|
||||
len -= 2;
|
||||
} else if (inform == MBSTRING_UNIV) {
|
||||
value = ((unsigned long)*p++) << 24;
|
||||
value |= ((unsigned long)*p++) << 16;
|
||||
value |= *p++ << 8;
|
||||
value |= *p++;
|
||||
len -= 4;
|
||||
} else {
|
||||
ret = UTF8_getc(p, len, &value);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
len -= ret;
|
||||
p += ret;
|
||||
}
|
||||
if (rfunc) {
|
||||
ret = rfunc(value, arg);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Various utility functions for traverse_string */
|
||||
|
||||
/* Just count number of characters */
|
||||
|
||||
static int in_utf8(unsigned long value, void *arg)
|
||||
{
|
||||
int *nchar;
|
||||
|
||||
if (!is_unicode_valid(value))
|
||||
return -2;
|
||||
nchar = arg;
|
||||
(*nchar)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Determine size of output as a UTF8 String */
|
||||
|
||||
static int out_utf8(unsigned long value, void *arg)
|
||||
{
|
||||
int *outlen, len;
|
||||
|
||||
len = UTF8_putc(NULL, -1, value);
|
||||
if (len <= 0)
|
||||
return len;
|
||||
outlen = arg;
|
||||
*outlen += len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine the "type" of a string: check each character against a supplied
|
||||
* "mask".
|
||||
*/
|
||||
|
||||
static int type_str(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned long types = *((unsigned long *)arg);
|
||||
const int native = value > INT_MAX ? INT_MAX : ossl_fromascii(value);
|
||||
|
||||
if ((types & B_ASN1_NUMERICSTRING) && !(ossl_isdigit(native)
|
||||
|| native == ' '))
|
||||
types &= ~B_ASN1_NUMERICSTRING;
|
||||
if ((types & B_ASN1_PRINTABLESTRING) && !ossl_isasn1print(native))
|
||||
types &= ~B_ASN1_PRINTABLESTRING;
|
||||
if ((types & B_ASN1_IA5STRING) && !ossl_isascii(native))
|
||||
types &= ~B_ASN1_IA5STRING;
|
||||
if ((types & B_ASN1_T61STRING) && (value > 0xff))
|
||||
types &= ~B_ASN1_T61STRING;
|
||||
if ((types & B_ASN1_BMPSTRING) && (value > 0xffff))
|
||||
types &= ~B_ASN1_BMPSTRING;
|
||||
if ((types & B_ASN1_UTF8STRING) && !is_unicode_valid(value))
|
||||
types &= ~B_ASN1_UTF8STRING;
|
||||
if (!types)
|
||||
return -1;
|
||||
*((unsigned long *)arg) = types;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy one byte per character ASCII like strings */
|
||||
|
||||
static int cpy_asc(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned char **p, *q;
|
||||
p = arg;
|
||||
q = *p;
|
||||
*q = (unsigned char)value;
|
||||
(*p)++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy two byte per character BMPStrings */
|
||||
|
||||
static int cpy_bmp(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned char **p, *q;
|
||||
p = arg;
|
||||
q = *p;
|
||||
*q++ = (unsigned char)((value >> 8) & 0xff);
|
||||
*q = (unsigned char)(value & 0xff);
|
||||
*p += 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy four byte per character UniversalStrings */
|
||||
|
||||
static int cpy_univ(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned char **p, *q;
|
||||
p = arg;
|
||||
q = *p;
|
||||
*q++ = (unsigned char)((value >> 24) & 0xff);
|
||||
*q++ = (unsigned char)((value >> 16) & 0xff);
|
||||
*q++ = (unsigned char)((value >> 8) & 0xff);
|
||||
*q = (unsigned char)(value & 0xff);
|
||||
*p += 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy to a UTF8String */
|
||||
|
||||
static int cpy_utf8(unsigned long value, void *arg)
|
||||
{
|
||||
unsigned char **p;
|
||||
int ret;
|
||||
p = arg;
|
||||
/* We already know there is enough room so pass 0xff as the length */
|
||||
ret = UTF8_putc(*p, 0xff, value);
|
||||
*p += ret;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include "crypto/ctype.h"
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/bn.h>
|
||||
#include "crypto/asn1.h"
|
||||
#include "asn1_local.h"
|
||||
|
||||
int i2d_ASN1_OBJECT(const ASN1_OBJECT *a, unsigned char **pp)
|
||||
{
|
||||
unsigned char *p, *allocated = NULL;
|
||||
int objsize;
|
||||
|
||||
if ((a == NULL) || (a->data == NULL))
|
||||
return 0;
|
||||
|
||||
objsize = ASN1_object_size(0, a->length, V_ASN1_OBJECT);
|
||||
if (pp == NULL || objsize == -1)
|
||||
return objsize;
|
||||
|
||||
if (*pp == NULL) {
|
||||
if ((p = allocated = OPENSSL_malloc(objsize)) == NULL)
|
||||
return 0;
|
||||
} else {
|
||||
p = *pp;
|
||||
}
|
||||
|
||||
ASN1_put_object(&p, 0, a->length, V_ASN1_OBJECT, V_ASN1_UNIVERSAL);
|
||||
memcpy(p, a->data, a->length);
|
||||
|
||||
/*
|
||||
* If a new buffer was allocated, just return it back.
|
||||
* If not, return the incremented buffer pointer.
|
||||
*/
|
||||
*pp = allocated != NULL ? allocated : p + a->length;
|
||||
return objsize;
|
||||
}
|
||||
|
||||
int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num)
|
||||
{
|
||||
int i, first, len = 0, c, use_bn;
|
||||
char ftmp[24], *tmp = ftmp;
|
||||
int tmpsize = sizeof(ftmp);
|
||||
const char *p;
|
||||
unsigned long l;
|
||||
BIGNUM *bl = NULL;
|
||||
|
||||
if (num == 0)
|
||||
return 0;
|
||||
else if (num == -1)
|
||||
num = strlen(buf);
|
||||
|
||||
p = buf;
|
||||
c = *(p++);
|
||||
num--;
|
||||
if ((c >= '0') && (c <= '2')) {
|
||||
first = c - '0';
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_FIRST_NUM_TOO_LARGE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (num <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_MISSING_SECOND_NUMBER);
|
||||
goto err;
|
||||
}
|
||||
c = *(p++);
|
||||
num--;
|
||||
for (;;) {
|
||||
if (num <= 0)
|
||||
break;
|
||||
if ((c != '.') && (c != ' ')) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_SEPARATOR);
|
||||
goto err;
|
||||
}
|
||||
l = 0;
|
||||
use_bn = 0;
|
||||
for (;;) {
|
||||
if (num <= 0)
|
||||
break;
|
||||
num--;
|
||||
c = *(p++);
|
||||
if ((c == ' ') || (c == '.'))
|
||||
break;
|
||||
if (!ossl_isdigit(c)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_DIGIT);
|
||||
goto err;
|
||||
}
|
||||
if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) {
|
||||
use_bn = 1;
|
||||
if (bl == NULL)
|
||||
bl = BN_new();
|
||||
if (bl == NULL || !BN_set_word(bl, l))
|
||||
goto err;
|
||||
}
|
||||
if (use_bn) {
|
||||
if (!BN_mul_word(bl, 10L)
|
||||
|| !BN_add_word(bl, c - '0'))
|
||||
goto err;
|
||||
} else
|
||||
l = l * 10L + (long)(c - '0');
|
||||
}
|
||||
if (len == 0) {
|
||||
if ((first < 2) && (l >= 40)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE);
|
||||
goto err;
|
||||
}
|
||||
if (use_bn) {
|
||||
if (!BN_add_word(bl, first * 40))
|
||||
goto err;
|
||||
} else
|
||||
l += (long)first *40;
|
||||
}
|
||||
i = 0;
|
||||
if (use_bn) {
|
||||
int blsize;
|
||||
blsize = BN_num_bits(bl);
|
||||
blsize = (blsize + 6) / 7;
|
||||
if (blsize > tmpsize) {
|
||||
if (tmp != ftmp)
|
||||
OPENSSL_free(tmp);
|
||||
tmpsize = blsize + 32;
|
||||
tmp = OPENSSL_malloc(tmpsize);
|
||||
if (tmp == NULL)
|
||||
goto err;
|
||||
}
|
||||
while (blsize--) {
|
||||
BN_ULONG t = BN_div_word(bl, 0x80L);
|
||||
if (t == (BN_ULONG)-1)
|
||||
goto err;
|
||||
tmp[i++] = (unsigned char)t;
|
||||
}
|
||||
} else {
|
||||
|
||||
for (;;) {
|
||||
tmp[i++] = (unsigned char)l & 0x7f;
|
||||
l >>= 7L;
|
||||
if (l == 0L)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (out != NULL) {
|
||||
if (len + i > olen) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_BUFFER_TOO_SMALL);
|
||||
goto err;
|
||||
}
|
||||
while (--i > 0)
|
||||
out[len++] = tmp[i] | 0x80;
|
||||
out[len++] = tmp[0];
|
||||
} else
|
||||
len += i;
|
||||
}
|
||||
if (tmp != ftmp)
|
||||
OPENSSL_free(tmp);
|
||||
BN_free(bl);
|
||||
return len;
|
||||
err:
|
||||
if (tmp != ftmp)
|
||||
OPENSSL_free(tmp);
|
||||
BN_free(bl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2t_ASN1_OBJECT(char *buf, int buf_len, const ASN1_OBJECT *a)
|
||||
{
|
||||
return OBJ_obj2txt(buf, buf_len, a, 0);
|
||||
}
|
||||
|
||||
int i2a_ASN1_OBJECT(BIO *bp, const ASN1_OBJECT *a)
|
||||
{
|
||||
char buf[80], *p = buf;
|
||||
int i;
|
||||
|
||||
if ((a == NULL) || (a->data == NULL))
|
||||
return BIO_write(bp, "NULL", 4);
|
||||
i = i2t_ASN1_OBJECT(buf, sizeof(buf), a);
|
||||
if (i > (int)(sizeof(buf) - 1)) {
|
||||
if (i > INT_MAX - 1) { /* catch an integer overflow */
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_LENGTH_TOO_LONG);
|
||||
return -1;
|
||||
}
|
||||
if ((p = OPENSSL_malloc(i + 1)) == NULL)
|
||||
return -1;
|
||||
i2t_ASN1_OBJECT(p, i + 1, a);
|
||||
}
|
||||
if (i <= 0) {
|
||||
i = BIO_write(bp, "<INVALID>", 9);
|
||||
if (i > 0)
|
||||
i += BIO_dump(bp, (const char *)a->data, a->length);
|
||||
return i;
|
||||
}
|
||||
BIO_write(bp, p, i);
|
||||
if (p != buf)
|
||||
OPENSSL_free(p);
|
||||
return i;
|
||||
}
|
||||
|
||||
ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
const unsigned char *p;
|
||||
long len;
|
||||
int tag, xclass;
|
||||
int inf, i;
|
||||
ASN1_OBJECT *ret = NULL;
|
||||
p = *pp;
|
||||
inf = ASN1_get_object(&p, &len, &tag, &xclass, length);
|
||||
if (inf & 0x80) {
|
||||
i = ASN1_R_BAD_OBJECT_HEADER;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (tag != V_ASN1_OBJECT) {
|
||||
i = ASN1_R_EXPECTING_AN_OBJECT;
|
||||
goto err;
|
||||
}
|
||||
ret = ossl_c2i_ASN1_OBJECT(a, &p, len);
|
||||
if (ret)
|
||||
*pp = p;
|
||||
return ret;
|
||||
err:
|
||||
ERR_raise(ERR_LIB_ASN1, i);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASN1_OBJECT *ossl_c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
|
||||
long len)
|
||||
{
|
||||
ASN1_OBJECT *ret = NULL, tobj;
|
||||
const unsigned char *p;
|
||||
unsigned char *data;
|
||||
int i, length;
|
||||
|
||||
/*
|
||||
* Sanity check OID encoding. Need at least one content octet. MSB must
|
||||
* be clear in the last octet. can't have leading 0x80 in subidentifiers,
|
||||
* see: X.690 8.19.2
|
||||
*/
|
||||
if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL ||
|
||||
p[len - 1] & 0x80) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_OBJECT_ENCODING);
|
||||
return NULL;
|
||||
}
|
||||
/* Now 0 < len <= INT_MAX, so the cast is safe. */
|
||||
length = (int)len;
|
||||
/*
|
||||
* Try to lookup OID in table: these are all valid encodings so if we get
|
||||
* a match we know the OID is valid.
|
||||
*/
|
||||
tobj.nid = NID_undef;
|
||||
tobj.data = p;
|
||||
tobj.length = length;
|
||||
tobj.flags = 0;
|
||||
i = OBJ_obj2nid(&tobj);
|
||||
if (i != NID_undef) {
|
||||
/*
|
||||
* Return shared registered OID object: this improves efficiency
|
||||
* because we don't have to return a dynamically allocated OID
|
||||
* and NID lookups can use the cached value.
|
||||
*/
|
||||
ret = OBJ_nid2obj(i);
|
||||
if (a) {
|
||||
ASN1_OBJECT_free(*a);
|
||||
*a = ret;
|
||||
}
|
||||
*pp += len;
|
||||
return ret;
|
||||
}
|
||||
for (i = 0; i < length; i++, p++) {
|
||||
if (*p == 0x80 && (!i || !(p[-1] & 0x80))) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_OBJECT_ENCODING);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((a == NULL) || ((*a) == NULL) ||
|
||||
!((*a)->flags & ASN1_OBJECT_FLAG_DYNAMIC)) {
|
||||
if ((ret = ASN1_OBJECT_new()) == NULL)
|
||||
return NULL;
|
||||
} else {
|
||||
ret = (*a);
|
||||
}
|
||||
|
||||
p = *pp;
|
||||
/* detach data from object */
|
||||
data = (unsigned char *)ret->data;
|
||||
ret->data = NULL;
|
||||
/* once detached we can change it */
|
||||
if ((data == NULL) || (ret->length < length)) {
|
||||
ret->length = 0;
|
||||
OPENSSL_free(data);
|
||||
data = OPENSSL_malloc(length);
|
||||
if (data == NULL)
|
||||
goto err;
|
||||
ret->flags |= ASN1_OBJECT_FLAG_DYNAMIC_DATA;
|
||||
}
|
||||
memcpy(data, p, length);
|
||||
/* If there are dynamic strings, free them here, and clear the flag */
|
||||
if ((ret->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) != 0) {
|
||||
OPENSSL_free((char *)ret->sn);
|
||||
OPENSSL_free((char *)ret->ln);
|
||||
ret->flags &= ~ASN1_OBJECT_FLAG_DYNAMIC_STRINGS;
|
||||
}
|
||||
/* reattach data to object, after which it remains const */
|
||||
ret->data = data;
|
||||
ret->length = length;
|
||||
ret->sn = NULL;
|
||||
ret->ln = NULL;
|
||||
/* ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; we know it is dynamic */
|
||||
p += length;
|
||||
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
*pp = p;
|
||||
return ret;
|
||||
err:
|
||||
ERR_raise(ERR_LIB_ASN1, i);
|
||||
if ((a == NULL) || (*a != ret))
|
||||
ASN1_OBJECT_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASN1_OBJECT *ASN1_OBJECT_new(void)
|
||||
{
|
||||
ASN1_OBJECT *ret;
|
||||
|
||||
ret = OPENSSL_zalloc(sizeof(*ret));
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
ret->flags = ASN1_OBJECT_FLAG_DYNAMIC;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ASN1_OBJECT_free(ASN1_OBJECT *a)
|
||||
{
|
||||
if (a == NULL)
|
||||
return;
|
||||
if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) {
|
||||
#ifndef CONST_STRICT
|
||||
/*
|
||||
* Disable purely for compile-time strict const checking. Doing this
|
||||
* on a "real" compile will cause memory leaks
|
||||
*/
|
||||
OPENSSL_free((void*)a->sn);
|
||||
OPENSSL_free((void*)a->ln);
|
||||
#endif
|
||||
a->sn = a->ln = NULL;
|
||||
}
|
||||
if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_DATA) {
|
||||
OPENSSL_free((void*)a->data);
|
||||
a->data = NULL;
|
||||
a->length = 0;
|
||||
}
|
||||
if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC)
|
||||
OPENSSL_free(a);
|
||||
}
|
||||
|
||||
ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data, int len,
|
||||
const char *sn, const char *ln)
|
||||
{
|
||||
ASN1_OBJECT o;
|
||||
|
||||
o.sn = sn;
|
||||
o.ln = ln;
|
||||
o.data = data;
|
||||
o.nid = nid;
|
||||
o.length = len;
|
||||
o.flags = ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
|
||||
ASN1_OBJECT_FLAG_DYNAMIC_DATA;
|
||||
return OBJ_dup(&o);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *x)
|
||||
{
|
||||
return ASN1_STRING_dup(x);
|
||||
}
|
||||
|
||||
int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a,
|
||||
const ASN1_OCTET_STRING *b)
|
||||
{
|
||||
return ASN1_STRING_cmp(a, b);
|
||||
}
|
||||
|
||||
int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *x, const unsigned char *d,
|
||||
int len)
|
||||
{
|
||||
return ASN1_STRING_set(x, d, len);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "crypto/ctype.h"
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
int ASN1_PRINTABLE_type(const unsigned char *s, int len)
|
||||
{
|
||||
int c;
|
||||
int ia5 = 0;
|
||||
int t61 = 0;
|
||||
|
||||
if (s == NULL)
|
||||
return V_ASN1_PRINTABLESTRING;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen((const char *)s);
|
||||
|
||||
while (len-- > 0) {
|
||||
c = *(s++);
|
||||
if (!ossl_isasn1print(c))
|
||||
ia5 = 1;
|
||||
if (!ossl_isascii(c))
|
||||
t61 = 1;
|
||||
}
|
||||
if (t61)
|
||||
return V_ASN1_T61STRING;
|
||||
if (ia5)
|
||||
return V_ASN1_IA5STRING;
|
||||
return V_ASN1_PRINTABLESTRING;
|
||||
}
|
||||
|
||||
int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s)
|
||||
{
|
||||
int i;
|
||||
unsigned char *p;
|
||||
|
||||
if (s->type != V_ASN1_UNIVERSALSTRING)
|
||||
return 0;
|
||||
if ((s->length % 4) != 0)
|
||||
return 0;
|
||||
p = s->data;
|
||||
for (i = 0; i < s->length; i += 4) {
|
||||
if ((p[0] != '\0') || (p[1] != '\0') || (p[2] != '\0'))
|
||||
break;
|
||||
else
|
||||
p += 4;
|
||||
}
|
||||
if (i < s->length)
|
||||
return 0;
|
||||
p = s->data;
|
||||
for (i = 3; i < s->length; i += 4) {
|
||||
*(p++) = s->data[i];
|
||||
}
|
||||
*(p) = '\0';
|
||||
s->length /= 4;
|
||||
s->type = ASN1_PRINTABLE_type(s->data, s->length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v)
|
||||
{
|
||||
int i, n;
|
||||
char buf[80];
|
||||
const char *p;
|
||||
|
||||
if (v == NULL)
|
||||
return 0;
|
||||
n = 0;
|
||||
p = (const char *)v->data;
|
||||
for (i = 0; i < v->length; i++) {
|
||||
if ((p[i] > '~') || ((p[i] < ' ') &&
|
||||
(p[i] != '\n') && (p[i] != '\r')))
|
||||
buf[n] = '.';
|
||||
else
|
||||
buf[n] = p[i];
|
||||
n++;
|
||||
if (n >= 80) {
|
||||
if (BIO_write(bp, buf, n) <= 0)
|
||||
return 0;
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
if (n > 0)
|
||||
if (BIO_write(bp, buf, n) <= 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/core_names.h>
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/evp.h"
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
|
||||
int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1, X509_ALGOR *algor2,
|
||||
ASN1_BIT_STRING *signature, char *data, EVP_PKEY *pkey,
|
||||
const EVP_MD *type)
|
||||
{
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||
unsigned char *p, *buf_in = NULL, *buf_out = NULL;
|
||||
int i, inl = 0, outl = 0;
|
||||
size_t inll = 0, outll = 0;
|
||||
X509_ALGOR *a;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (i == 0)
|
||||
a = algor1;
|
||||
else
|
||||
a = algor2;
|
||||
if (a == NULL)
|
||||
continue;
|
||||
if (type->pkey_type == NID_dsaWithSHA1) {
|
||||
/*
|
||||
* special case: RFC 2459 tells us to omit 'parameters' with
|
||||
* id-dsa-with-sha1
|
||||
*/
|
||||
ASN1_TYPE_free(a->parameter);
|
||||
a->parameter = NULL;
|
||||
} else if ((a->parameter == NULL) ||
|
||||
(a->parameter->type != V_ASN1_NULL)) {
|
||||
ASN1_TYPE_free(a->parameter);
|
||||
if ((a->parameter = ASN1_TYPE_new()) == NULL)
|
||||
goto err;
|
||||
a->parameter->type = V_ASN1_NULL;
|
||||
}
|
||||
ASN1_OBJECT_free(a->algorithm);
|
||||
a->algorithm = OBJ_nid2obj(type->pkey_type);
|
||||
if (a->algorithm == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_OBJECT_TYPE);
|
||||
goto err;
|
||||
}
|
||||
if (a->algorithm->length == 0) {
|
||||
ERR_raise(ERR_LIB_ASN1,
|
||||
ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
inl = i2d(data, NULL);
|
||||
if (inl <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
inll = (size_t)inl;
|
||||
buf_in = OPENSSL_malloc(inll);
|
||||
outll = outl = EVP_PKEY_get_size(pkey);
|
||||
buf_out = OPENSSL_malloc(outll);
|
||||
if (buf_in == NULL || buf_out == NULL) {
|
||||
outl = 0;
|
||||
goto err;
|
||||
}
|
||||
p = buf_in;
|
||||
|
||||
i2d(data, &p);
|
||||
if (!EVP_SignInit_ex(ctx, type, NULL)
|
||||
|| !EVP_SignUpdate(ctx, (unsigned char *)buf_in, inl)
|
||||
|| !EVP_SignFinal(ctx, (unsigned char *)buf_out,
|
||||
(unsigned int *)&outl, pkey)) {
|
||||
outl = 0;
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
ASN1_STRING_set0(signature, buf_out, outl);
|
||||
buf_out = NULL;
|
||||
/*
|
||||
* In the interests of compatibility, I'll make sure that the bit string
|
||||
* has a 'not-used bits' value of 0
|
||||
*/
|
||||
ossl_asn1_string_set_bits_left(signature, 0);
|
||||
err:
|
||||
EVP_MD_CTX_free(ctx);
|
||||
OPENSSL_clear_free((char *)buf_in, inll);
|
||||
OPENSSL_clear_free((char *)buf_out, outll);
|
||||
return outl;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
|
||||
ASN1_BIT_STRING *signature, const void *data,
|
||||
EVP_PKEY *pkey, const EVP_MD *md)
|
||||
{
|
||||
return ASN1_item_sign_ex(it, algor1, algor2, signature, data, NULL, pkey,
|
||||
md, NULL, NULL);
|
||||
}
|
||||
|
||||
int ASN1_item_sign_ex(const ASN1_ITEM *it, X509_ALGOR *algor1,
|
||||
X509_ALGOR *algor2, ASN1_BIT_STRING *signature,
|
||||
const void *data, const ASN1_OCTET_STRING *id,
|
||||
EVP_PKEY *pkey, const EVP_MD *md, OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
int rv = 0;
|
||||
EVP_MD_CTX *ctx = evp_md_ctx_new_ex(pkey, id, libctx, propq);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
return 0;
|
||||
}
|
||||
/* We can use the non _ex variant here since the pkey is already setup */
|
||||
if (!EVP_DigestSignInit(ctx, NULL, md, NULL, pkey))
|
||||
goto err;
|
||||
|
||||
rv = ASN1_item_sign_ctx(it, algor1, algor2, signature, data, ctx);
|
||||
|
||||
err:
|
||||
EVP_PKEY_CTX_free(EVP_MD_CTX_get_pkey_ctx(ctx));
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ASN1_item_sign_ctx(const ASN1_ITEM *it, X509_ALGOR *algor1,
|
||||
X509_ALGOR *algor2, ASN1_BIT_STRING *signature,
|
||||
const void *data, EVP_MD_CTX *ctx)
|
||||
{
|
||||
const EVP_MD *md;
|
||||
EVP_PKEY *pkey;
|
||||
unsigned char *buf_in = NULL, *buf_out = NULL;
|
||||
size_t inl = 0, outl = 0, outll = 0;
|
||||
int signid, paramtype, buf_len = 0;
|
||||
int rv, pkey_id;
|
||||
|
||||
md = EVP_MD_CTX_get0_md(ctx);
|
||||
pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx));
|
||||
|
||||
if (pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_CONTEXT_NOT_INITIALISED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pkey->ameth == NULL) {
|
||||
EVP_PKEY_CTX *pctx = EVP_MD_CTX_get_pkey_ctx(ctx);
|
||||
OSSL_PARAM params[2];
|
||||
unsigned char aid[128];
|
||||
size_t aid_len = 0;
|
||||
|
||||
if (pctx == NULL
|
||||
|| !EVP_PKEY_CTX_IS_SIGNATURE_OP(pctx)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_CONTEXT_NOT_INITIALISED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
params[0] =
|
||||
OSSL_PARAM_construct_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID,
|
||||
aid, sizeof(aid));
|
||||
params[1] = OSSL_PARAM_construct_end();
|
||||
|
||||
if (EVP_PKEY_CTX_get_params(pctx, params) <= 0)
|
||||
goto err;
|
||||
|
||||
if ((aid_len = params[0].return_size) == 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (algor1 != NULL) {
|
||||
const unsigned char *pp = aid;
|
||||
|
||||
if (d2i_X509_ALGOR(&algor1, &pp, aid_len) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (algor2 != NULL) {
|
||||
const unsigned char *pp = aid;
|
||||
|
||||
if (d2i_X509_ALGOR(&algor2, &pp, aid_len) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
rv = 3;
|
||||
} else if (pkey->ameth->item_sign) {
|
||||
rv = pkey->ameth->item_sign(ctx, it, data, algor1, algor2, signature);
|
||||
if (rv == 1)
|
||||
outl = signature->length;
|
||||
/*-
|
||||
* Return value meanings:
|
||||
* <=0: error.
|
||||
* 1: method does everything.
|
||||
* 2: carry on as normal.
|
||||
* 3: ASN1 method sets algorithm identifiers: just sign.
|
||||
*/
|
||||
if (rv <= 0)
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
if (rv <= 1)
|
||||
goto err;
|
||||
} else {
|
||||
rv = 2;
|
||||
}
|
||||
|
||||
if (rv == 2) {
|
||||
if (md == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_CONTEXT_NOT_INITIALISED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
pkey_id =
|
||||
#ifndef OPENSSL_NO_SM2
|
||||
EVP_PKEY_get_id(pkey) == NID_sm2 ? NID_sm2 :
|
||||
#endif
|
||||
pkey->ameth->pkey_id;
|
||||
|
||||
if (!OBJ_find_sigid_by_algs(&signid, EVP_MD_nid(md), pkey_id)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
paramtype = pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL ?
|
||||
V_ASN1_NULL : V_ASN1_UNDEF;
|
||||
if (algor1 != NULL
|
||||
&& !X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL))
|
||||
goto err;
|
||||
if (algor2 != NULL
|
||||
&& !X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL))
|
||||
goto err;
|
||||
}
|
||||
|
||||
buf_len = ASN1_item_i2d(data, &buf_in, it);
|
||||
if (buf_len <= 0) {
|
||||
outl = 0;
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
inl = buf_len;
|
||||
if (!EVP_DigestSign(ctx, NULL, &outll, buf_in, inl)) {
|
||||
outl = 0;
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
outl = outll;
|
||||
buf_out = OPENSSL_malloc(outll);
|
||||
if (buf_in == NULL || buf_out == NULL) {
|
||||
outl = 0;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!EVP_DigestSign(ctx, buf_out, &outl, buf_in, inl)) {
|
||||
outl = 0;
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
ASN1_STRING_set0(signature, buf_out, outl);
|
||||
buf_out = NULL;
|
||||
/*
|
||||
* In the interests of compatibility, I'll make sure that the bit string
|
||||
* has a 'not-used bits' value of 0
|
||||
*/
|
||||
ossl_asn1_string_set_bits_left(signature, 0);
|
||||
err:
|
||||
OPENSSL_clear_free((char *)buf_in, inl);
|
||||
OPENSSL_clear_free((char *)buf_out, outll);
|
||||
return outl;
|
||||
}
|
||||
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
* Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/sizes.h"
|
||||
#include "crypto/asn1.h"
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#include "charmap.h"
|
||||
|
||||
/*
|
||||
* ASN1_STRING_print_ex() and X509_NAME_print_ex(). Enhanced string and name
|
||||
* printing routines handling multibyte characters, RFC2253 and a host of
|
||||
* other options.
|
||||
*/
|
||||
|
||||
#define CHARTYPE_BS_ESC (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253)
|
||||
|
||||
#define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \
|
||||
ASN1_STRFLGS_ESC_2254 | \
|
||||
ASN1_STRFLGS_ESC_QUOTE | \
|
||||
ASN1_STRFLGS_ESC_CTRL | \
|
||||
ASN1_STRFLGS_ESC_MSB)
|
||||
|
||||
/*
|
||||
* Three IO functions for sending data to memory, a BIO and a FILE
|
||||
* pointer.
|
||||
*/
|
||||
static int send_bio_chars(void *arg, const void *buf, int len)
|
||||
{
|
||||
if (!arg)
|
||||
return 1;
|
||||
if (BIO_write(arg, buf, len) != len)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_STDIO
|
||||
static int send_fp_chars(void *arg, const void *buf, int len)
|
||||
{
|
||||
if (!arg)
|
||||
return 1;
|
||||
if (fwrite(buf, 1, len, arg) != (unsigned int)len)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef int char_io (void *arg, const void *buf, int len);
|
||||
|
||||
/*
|
||||
* This function handles display of strings, one character at a time. It is
|
||||
* passed an unsigned long for each character because it could come from 2 or
|
||||
* even 4 byte forms.
|
||||
*/
|
||||
|
||||
static int do_esc_char(unsigned long c, unsigned short flags, char *do_quotes,
|
||||
char_io *io_ch, void *arg)
|
||||
{
|
||||
unsigned short chflgs;
|
||||
unsigned char chtmp;
|
||||
char tmphex[HEX_SIZE(long) + 3];
|
||||
|
||||
if (c > 0xffffffffL)
|
||||
return -1;
|
||||
if (c > 0xffff) {
|
||||
BIO_snprintf(tmphex, sizeof(tmphex), "\\W%08lX", c);
|
||||
if (!io_ch(arg, tmphex, 10))
|
||||
return -1;
|
||||
return 10;
|
||||
}
|
||||
if (c > 0xff) {
|
||||
BIO_snprintf(tmphex, sizeof(tmphex), "\\U%04lX", c);
|
||||
if (!io_ch(arg, tmphex, 6))
|
||||
return -1;
|
||||
return 6;
|
||||
}
|
||||
chtmp = (unsigned char)c;
|
||||
if (chtmp > 0x7f)
|
||||
chflgs = flags & ASN1_STRFLGS_ESC_MSB;
|
||||
else
|
||||
chflgs = char_type[chtmp] & flags;
|
||||
if (chflgs & CHARTYPE_BS_ESC) {
|
||||
/* If we don't escape with quotes, signal we need quotes */
|
||||
if (chflgs & ASN1_STRFLGS_ESC_QUOTE) {
|
||||
if (do_quotes)
|
||||
*do_quotes = 1;
|
||||
if (!io_ch(arg, &chtmp, 1))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
if (!io_ch(arg, "\\", 1))
|
||||
return -1;
|
||||
if (!io_ch(arg, &chtmp, 1))
|
||||
return -1;
|
||||
return 2;
|
||||
}
|
||||
if (chflgs & (ASN1_STRFLGS_ESC_CTRL
|
||||
| ASN1_STRFLGS_ESC_MSB
|
||||
| ASN1_STRFLGS_ESC_2254)) {
|
||||
BIO_snprintf(tmphex, 11, "\\%02X", chtmp);
|
||||
if (!io_ch(arg, tmphex, 3))
|
||||
return -1;
|
||||
return 3;
|
||||
}
|
||||
/*
|
||||
* If we get this far and do any escaping at all must escape the escape
|
||||
* character itself: backslash.
|
||||
*/
|
||||
if (chtmp == '\\' && (flags & ESC_FLAGS)) {
|
||||
if (!io_ch(arg, "\\\\", 2))
|
||||
return -1;
|
||||
return 2;
|
||||
}
|
||||
if (!io_ch(arg, &chtmp, 1))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define BUF_TYPE_WIDTH_MASK 0x7
|
||||
#define BUF_TYPE_CONVUTF8 0x8
|
||||
|
||||
/*
|
||||
* This function sends each character in a buffer to do_esc_char(). It
|
||||
* interprets the content formats and converts to or from UTF8 as
|
||||
* appropriate.
|
||||
*/
|
||||
|
||||
static int do_buf(unsigned char *buf, int buflen,
|
||||
int type, unsigned short flags, char *quotes, char_io *io_ch,
|
||||
void *arg)
|
||||
{
|
||||
int i, outlen, len, charwidth;
|
||||
unsigned short orflags;
|
||||
unsigned char *p, *q;
|
||||
unsigned long c;
|
||||
|
||||
p = buf;
|
||||
q = buf + buflen;
|
||||
outlen = 0;
|
||||
charwidth = type & BUF_TYPE_WIDTH_MASK;
|
||||
|
||||
switch (charwidth) {
|
||||
case 4:
|
||||
if (buflen & 3) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (buflen & 1) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
while (p != q) {
|
||||
if (p == buf && flags & ASN1_STRFLGS_ESC_2253)
|
||||
orflags = CHARTYPE_FIRST_ESC_2253;
|
||||
else
|
||||
orflags = 0;
|
||||
|
||||
switch (charwidth) {
|
||||
case 4:
|
||||
c = ((unsigned long)*p++) << 24;
|
||||
c |= ((unsigned long)*p++) << 16;
|
||||
c |= ((unsigned long)*p++) << 8;
|
||||
c |= *p++;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
c = ((unsigned long)*p++) << 8;
|
||||
c |= *p++;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
c = *p++;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
i = UTF8_getc(p, buflen, &c);
|
||||
if (i < 0)
|
||||
return -1; /* Invalid UTF8String */
|
||||
buflen -= i;
|
||||
p += i;
|
||||
break;
|
||||
default:
|
||||
return -1; /* invalid width */
|
||||
}
|
||||
if (p == q && flags & ASN1_STRFLGS_ESC_2253)
|
||||
orflags = CHARTYPE_LAST_ESC_2253;
|
||||
if (type & BUF_TYPE_CONVUTF8) {
|
||||
unsigned char utfbuf[6];
|
||||
int utflen;
|
||||
utflen = UTF8_putc(utfbuf, sizeof(utfbuf), c);
|
||||
for (i = 0; i < utflen; i++) {
|
||||
/*
|
||||
* We don't need to worry about setting orflags correctly
|
||||
* because if utflen==1 its value will be correct anyway
|
||||
* otherwise each character will be > 0x7f and so the
|
||||
* character will never be escaped on first and last.
|
||||
*/
|
||||
len = do_esc_char(utfbuf[i], flags | orflags, quotes,
|
||||
io_ch, arg);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
outlen += len;
|
||||
}
|
||||
} else {
|
||||
len = do_esc_char(c, flags | orflags, quotes,
|
||||
io_ch, arg);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
outlen += len;
|
||||
}
|
||||
}
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/* This function hex dumps a buffer of characters */
|
||||
|
||||
static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf,
|
||||
int buflen)
|
||||
{
|
||||
unsigned char *p, *q;
|
||||
char hextmp[2];
|
||||
|
||||
if (arg) {
|
||||
p = buf;
|
||||
q = buf + buflen;
|
||||
while (p != q) {
|
||||
ossl_to_hex(hextmp, *p);
|
||||
if (!io_ch(arg, hextmp, 2))
|
||||
return -1;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return buflen << 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* "dump" a string. This is done when the type is unknown, or the flags
|
||||
* request it. We can either dump the content octets or the entire DER
|
||||
* encoding. This uses the RFC2253 #01234 format.
|
||||
*/
|
||||
|
||||
static int do_dump(unsigned long lflags, char_io *io_ch, void *arg,
|
||||
const ASN1_STRING *str)
|
||||
{
|
||||
/*
|
||||
* Placing the ASN1_STRING in a temp ASN1_TYPE allows the DER encoding to
|
||||
* readily obtained
|
||||
*/
|
||||
ASN1_TYPE t;
|
||||
unsigned char *der_buf, *p;
|
||||
int outlen, der_len;
|
||||
|
||||
if (!io_ch(arg, "#", 1))
|
||||
return -1;
|
||||
/* If we don't dump DER encoding just dump content octets */
|
||||
if (!(lflags & ASN1_STRFLGS_DUMP_DER)) {
|
||||
outlen = do_hex_dump(io_ch, arg, str->data, str->length);
|
||||
if (outlen < 0)
|
||||
return -1;
|
||||
return outlen + 1;
|
||||
}
|
||||
t.type = str->type;
|
||||
t.value.ptr = (char *)str;
|
||||
der_len = i2d_ASN1_TYPE(&t, NULL);
|
||||
if (der_len <= 0)
|
||||
return -1;
|
||||
if ((der_buf = OPENSSL_malloc(der_len)) == NULL)
|
||||
return -1;
|
||||
p = der_buf;
|
||||
i2d_ASN1_TYPE(&t, &p);
|
||||
outlen = do_hex_dump(io_ch, arg, der_buf, der_len);
|
||||
OPENSSL_free(der_buf);
|
||||
if (outlen < 0)
|
||||
return -1;
|
||||
return outlen + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup table to convert tags to character widths, 0 = UTF8 encoded, -1 is
|
||||
* used for non string types otherwise it is the number of bytes per
|
||||
* character
|
||||
*/
|
||||
|
||||
static const signed char tag2nbyte[] = {
|
||||
-1, -1, -1, -1, -1, /* 0-4 */
|
||||
-1, -1, -1, -1, -1, /* 5-9 */
|
||||
-1, -1, /* 10-11 */
|
||||
0, /* 12 V_ASN1_UTF8STRING */
|
||||
-1, -1, -1, -1, -1, /* 13-17 */
|
||||
1, /* 18 V_ASN1_NUMERICSTRING */
|
||||
1, /* 19 V_ASN1_PRINTABLESTRING */
|
||||
1, /* 20 V_ASN1_T61STRING */
|
||||
-1, /* 21 */
|
||||
1, /* 22 V_ASN1_IA5STRING */
|
||||
1, /* 23 V_ASN1_UTCTIME */
|
||||
1, /* 24 V_ASN1_GENERALIZEDTIME */
|
||||
-1, /* 25 */
|
||||
1, /* 26 V_ASN1_ISO64STRING */
|
||||
-1, /* 27 */
|
||||
4, /* 28 V_ASN1_UNIVERSALSTRING */
|
||||
-1, /* 29 */
|
||||
2 /* 30 V_ASN1_BMPSTRING */
|
||||
};
|
||||
|
||||
/*
|
||||
* This is the main function, print out an ASN1_STRING taking note of various
|
||||
* escape and display options. Returns number of characters written or -1 if
|
||||
* an error occurred.
|
||||
*/
|
||||
|
||||
static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags,
|
||||
const ASN1_STRING *str)
|
||||
{
|
||||
int outlen, len;
|
||||
int type;
|
||||
char quotes;
|
||||
unsigned short flags;
|
||||
quotes = 0;
|
||||
/* Keep a copy of escape flags */
|
||||
flags = (unsigned short)(lflags & ESC_FLAGS);
|
||||
|
||||
type = str->type;
|
||||
|
||||
outlen = 0;
|
||||
|
||||
if (lflags & ASN1_STRFLGS_SHOW_TYPE) {
|
||||
const char *tagname;
|
||||
|
||||
tagname = ASN1_tag2str(type);
|
||||
/* We can directly cast here as tagname will never be too large. */
|
||||
outlen += (int)strlen(tagname);
|
||||
if (!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1))
|
||||
return -1;
|
||||
outlen++;
|
||||
}
|
||||
|
||||
/* Decide what to do with type, either dump content or display it */
|
||||
|
||||
/* Dump everything */
|
||||
if (lflags & ASN1_STRFLGS_DUMP_ALL)
|
||||
type = -1;
|
||||
/* Ignore the string type */
|
||||
else if (lflags & ASN1_STRFLGS_IGNORE_TYPE)
|
||||
type = 1;
|
||||
else {
|
||||
/* Else determine width based on type */
|
||||
if ((type > 0) && (type < 31))
|
||||
type = tag2nbyte[type];
|
||||
else
|
||||
type = -1;
|
||||
if ((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN))
|
||||
type = 1;
|
||||
}
|
||||
|
||||
if (type == -1) {
|
||||
len = do_dump(lflags, io_ch, arg, str);
|
||||
if (len < 0 || len > INT_MAX - outlen)
|
||||
return -1;
|
||||
outlen += len;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
if (lflags & ASN1_STRFLGS_UTF8_CONVERT) {
|
||||
/*
|
||||
* Note: if string is UTF8 and we want to convert to UTF8 then we
|
||||
* just interpret it as 1 byte per character to avoid converting
|
||||
* twice.
|
||||
*/
|
||||
if (!type)
|
||||
type = 1;
|
||||
else
|
||||
type |= BUF_TYPE_CONVUTF8;
|
||||
}
|
||||
|
||||
len = do_buf(str->data, str->length, type, flags, "es, io_ch, NULL);
|
||||
if (len < 0 || len > INT_MAX - 2 - outlen)
|
||||
return -1;
|
||||
outlen += len;
|
||||
if (quotes)
|
||||
outlen += 2;
|
||||
if (!arg)
|
||||
return outlen;
|
||||
if (quotes && !io_ch(arg, "\"", 1))
|
||||
return -1;
|
||||
if (do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0)
|
||||
return -1;
|
||||
if (quotes && !io_ch(arg, "\"", 1))
|
||||
return -1;
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/* Used for line indenting: print 'indent' spaces */
|
||||
|
||||
static int do_indent(char_io *io_ch, void *arg, int indent)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < indent; i++)
|
||||
if (!io_ch(arg, " ", 1))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define FN_WIDTH_LN 25
|
||||
#define FN_WIDTH_SN 10
|
||||
|
||||
static int do_name_ex(char_io *io_ch, void *arg, const X509_NAME *n,
|
||||
int indent, unsigned long flags)
|
||||
{
|
||||
int i, prev = -1, orflags, cnt;
|
||||
int fn_opt, fn_nid;
|
||||
ASN1_OBJECT *fn;
|
||||
const ASN1_STRING *val;
|
||||
const X509_NAME_ENTRY *ent;
|
||||
char objtmp[80];
|
||||
const char *objbuf;
|
||||
int outlen, len;
|
||||
char *sep_dn, *sep_mv, *sep_eq;
|
||||
int sep_dn_len, sep_mv_len, sep_eq_len;
|
||||
if (indent < 0)
|
||||
indent = 0;
|
||||
outlen = indent;
|
||||
if (!do_indent(io_ch, arg, indent))
|
||||
return -1;
|
||||
switch (flags & XN_FLAG_SEP_MASK) {
|
||||
case XN_FLAG_SEP_MULTILINE:
|
||||
sep_dn = "\n";
|
||||
sep_dn_len = 1;
|
||||
sep_mv = " + ";
|
||||
sep_mv_len = 3;
|
||||
break;
|
||||
|
||||
case XN_FLAG_SEP_COMMA_PLUS:
|
||||
sep_dn = ",";
|
||||
sep_dn_len = 1;
|
||||
sep_mv = "+";
|
||||
sep_mv_len = 1;
|
||||
indent = 0;
|
||||
break;
|
||||
|
||||
case XN_FLAG_SEP_CPLUS_SPC:
|
||||
sep_dn = ", ";
|
||||
sep_dn_len = 2;
|
||||
sep_mv = " + ";
|
||||
sep_mv_len = 3;
|
||||
indent = 0;
|
||||
break;
|
||||
|
||||
case XN_FLAG_SEP_SPLUS_SPC:
|
||||
sep_dn = "; ";
|
||||
sep_dn_len = 2;
|
||||
sep_mv = " + ";
|
||||
sep_mv_len = 3;
|
||||
indent = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags & XN_FLAG_SPC_EQ) {
|
||||
sep_eq = " = ";
|
||||
sep_eq_len = 3;
|
||||
} else {
|
||||
sep_eq = "=";
|
||||
sep_eq_len = 1;
|
||||
}
|
||||
|
||||
fn_opt = flags & XN_FLAG_FN_MASK;
|
||||
|
||||
cnt = X509_NAME_entry_count(n);
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (flags & XN_FLAG_DN_REV)
|
||||
ent = X509_NAME_get_entry(n, cnt - i - 1);
|
||||
else
|
||||
ent = X509_NAME_get_entry(n, i);
|
||||
if (prev != -1) {
|
||||
if (prev == X509_NAME_ENTRY_set(ent)) {
|
||||
if (!io_ch(arg, sep_mv, sep_mv_len))
|
||||
return -1;
|
||||
outlen += sep_mv_len;
|
||||
} else {
|
||||
if (!io_ch(arg, sep_dn, sep_dn_len))
|
||||
return -1;
|
||||
outlen += sep_dn_len;
|
||||
if (!do_indent(io_ch, arg, indent))
|
||||
return -1;
|
||||
outlen += indent;
|
||||
}
|
||||
}
|
||||
prev = X509_NAME_ENTRY_set(ent);
|
||||
fn = X509_NAME_ENTRY_get_object(ent);
|
||||
val = X509_NAME_ENTRY_get_data(ent);
|
||||
fn_nid = OBJ_obj2nid(fn);
|
||||
if (fn_opt != XN_FLAG_FN_NONE) {
|
||||
int objlen, fld_len;
|
||||
if ((fn_opt == XN_FLAG_FN_OID) || (fn_nid == NID_undef)) {
|
||||
OBJ_obj2txt(objtmp, sizeof(objtmp), fn, 1);
|
||||
fld_len = 0; /* XXX: what should this be? */
|
||||
objbuf = objtmp;
|
||||
} else {
|
||||
if (fn_opt == XN_FLAG_FN_SN) {
|
||||
fld_len = FN_WIDTH_SN;
|
||||
objbuf = OBJ_nid2sn(fn_nid);
|
||||
} else if (fn_opt == XN_FLAG_FN_LN) {
|
||||
fld_len = FN_WIDTH_LN;
|
||||
objbuf = OBJ_nid2ln(fn_nid);
|
||||
} else {
|
||||
fld_len = 0; /* XXX: what should this be? */
|
||||
objbuf = "";
|
||||
}
|
||||
}
|
||||
objlen = strlen(objbuf);
|
||||
if (!io_ch(arg, objbuf, objlen))
|
||||
return -1;
|
||||
if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) {
|
||||
if (!do_indent(io_ch, arg, fld_len - objlen))
|
||||
return -1;
|
||||
outlen += fld_len - objlen;
|
||||
}
|
||||
if (!io_ch(arg, sep_eq, sep_eq_len))
|
||||
return -1;
|
||||
outlen += objlen + sep_eq_len;
|
||||
}
|
||||
/*
|
||||
* If the field name is unknown then fix up the DER dump flag. We
|
||||
* might want to limit this further so it will DER dump on anything
|
||||
* other than a few 'standard' fields.
|
||||
*/
|
||||
if ((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS))
|
||||
orflags = ASN1_STRFLGS_DUMP_ALL;
|
||||
else
|
||||
orflags = 0;
|
||||
|
||||
len = do_print_ex(io_ch, arg, flags | orflags, val);
|
||||
if (len < 0)
|
||||
return -1;
|
||||
outlen += len;
|
||||
}
|
||||
return outlen;
|
||||
}
|
||||
|
||||
/* Wrappers round the main functions */
|
||||
|
||||
int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent,
|
||||
unsigned long flags)
|
||||
{
|
||||
if (flags == XN_FLAG_COMPAT)
|
||||
return X509_NAME_print(out, nm, indent);
|
||||
return do_name_ex(send_bio_chars, out, nm, indent, flags);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_STDIO
|
||||
int X509_NAME_print_ex_fp(FILE *fp, const X509_NAME *nm, int indent,
|
||||
unsigned long flags)
|
||||
{
|
||||
if (flags == XN_FLAG_COMPAT) {
|
||||
BIO *btmp;
|
||||
int ret;
|
||||
btmp = BIO_new_fp(fp, BIO_NOCLOSE);
|
||||
if (!btmp)
|
||||
return -1;
|
||||
ret = X509_NAME_print(btmp, nm, indent);
|
||||
BIO_free(btmp);
|
||||
return ret;
|
||||
}
|
||||
return do_name_ex(send_fp_chars, fp, nm, indent, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
int ASN1_STRING_print_ex(BIO *out, const ASN1_STRING *str, unsigned long flags)
|
||||
{
|
||||
return do_print_ex(send_bio_chars, out, flags, str);
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_STDIO
|
||||
int ASN1_STRING_print_ex_fp(FILE *fp, const ASN1_STRING *str, unsigned long flags)
|
||||
{
|
||||
return do_print_ex(send_fp_chars, fp, flags, str);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Utility function: convert any string type to UTF8, returns number of bytes
|
||||
* in output string or a negative error code
|
||||
*/
|
||||
|
||||
int ASN1_STRING_to_UTF8(unsigned char **out, const ASN1_STRING *in)
|
||||
{
|
||||
ASN1_STRING stmp, *str = &stmp;
|
||||
int mbflag, type, ret;
|
||||
if (!in)
|
||||
return -1;
|
||||
type = in->type;
|
||||
if ((type < 0) || (type > 30))
|
||||
return -1;
|
||||
mbflag = tag2nbyte[type];
|
||||
if (mbflag == -1)
|
||||
return -1;
|
||||
mbflag |= MBSTRING_FLAG;
|
||||
stmp.data = NULL;
|
||||
stmp.length = 0;
|
||||
stmp.flags = 0;
|
||||
ret =
|
||||
ASN1_mbstring_copy(&str, in->data, in->length, mbflag,
|
||||
B_ASN1_UTF8STRING);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
*out = stmp.data;
|
||||
return stmp.length;
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
* Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/objects.h>
|
||||
|
||||
static STACK_OF(ASN1_STRING_TABLE) *stable = NULL;
|
||||
static void st_free(ASN1_STRING_TABLE *tbl);
|
||||
static int sk_table_cmp(const ASN1_STRING_TABLE *const *a,
|
||||
const ASN1_STRING_TABLE *const *b);
|
||||
|
||||
/*
|
||||
* This is the global mask for the mbstring functions: this is use to mask
|
||||
* out certain types (such as BMPString and UTF8String) because certain
|
||||
* software (e.g. Netscape) has problems with them.
|
||||
*/
|
||||
|
||||
static unsigned long global_mask = B_ASN1_UTF8STRING;
|
||||
|
||||
void ASN1_STRING_set_default_mask(unsigned long mask)
|
||||
{
|
||||
global_mask = mask;
|
||||
}
|
||||
|
||||
unsigned long ASN1_STRING_get_default_mask(void)
|
||||
{
|
||||
return global_mask;
|
||||
}
|
||||
|
||||
/*-
|
||||
* This function sets the default to various "flavours" of configuration.
|
||||
* based on an ASCII string. Currently this is:
|
||||
* MASK:XXXX : a numerical mask value.
|
||||
* default : use Printable, IA5, T61, BMP, and UTF8 string types
|
||||
* nombstr : any string type except variable-sized BMPStrings or UTF8Strings
|
||||
* pkix : PKIX recommendation in RFC2459
|
||||
* utf8only : this is the default, use UTF8Strings
|
||||
*/
|
||||
|
||||
int ASN1_STRING_set_default_mask_asc(const char *p)
|
||||
{
|
||||
unsigned long mask;
|
||||
char *end;
|
||||
|
||||
if (CHECK_AND_SKIP_PREFIX(p, "MASK:")) {
|
||||
if (*p == '\0')
|
||||
return 0;
|
||||
mask = strtoul(p, &end, 0);
|
||||
if (*end)
|
||||
return 0;
|
||||
} else if (strcmp(p, "nombstr") == 0)
|
||||
mask = ~((unsigned long)(B_ASN1_BMPSTRING | B_ASN1_UTF8STRING));
|
||||
else if (strcmp(p, "pkix") == 0)
|
||||
mask = ~((unsigned long)B_ASN1_T61STRING);
|
||||
else if (strcmp(p, "utf8only") == 0)
|
||||
mask = B_ASN1_UTF8STRING;
|
||||
else if (strcmp(p, "default") == 0)
|
||||
mask = 0xFFFFFFFFL;
|
||||
else
|
||||
return 0;
|
||||
ASN1_STRING_set_default_mask(mask);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function generates an ASN1_STRING based on limits in a
|
||||
* table. Frequently the types and length of an ASN1_STRING are restricted by
|
||||
* a corresponding OID. For example certificates and certificate requests.
|
||||
*/
|
||||
|
||||
ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out,
|
||||
const unsigned char *in, int inlen,
|
||||
int inform, int nid)
|
||||
{
|
||||
ASN1_STRING_TABLE *tbl;
|
||||
ASN1_STRING *str = NULL;
|
||||
unsigned long mask;
|
||||
int ret;
|
||||
|
||||
if (out == NULL)
|
||||
out = &str;
|
||||
tbl = ASN1_STRING_TABLE_get(nid);
|
||||
if (tbl != NULL) {
|
||||
mask = tbl->mask;
|
||||
if (!(tbl->flags & STABLE_NO_MASK))
|
||||
mask &= global_mask;
|
||||
ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask,
|
||||
tbl->minsize, tbl->maxsize);
|
||||
} else {
|
||||
ret = ASN1_mbstring_copy(out, in, inlen, inform,
|
||||
DIRSTRING_TYPE & global_mask);
|
||||
}
|
||||
if (ret <= 0)
|
||||
return NULL;
|
||||
return *out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now the tables and helper functions for the string table:
|
||||
*/
|
||||
|
||||
#include "tbl_standard.h"
|
||||
|
||||
static int sk_table_cmp(const ASN1_STRING_TABLE *const *a,
|
||||
const ASN1_STRING_TABLE *const *b)
|
||||
{
|
||||
return (*a)->nid - (*b)->nid;
|
||||
}
|
||||
|
||||
DECLARE_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
|
||||
|
||||
static int table_cmp(const ASN1_STRING_TABLE *a, const ASN1_STRING_TABLE *b)
|
||||
{
|
||||
return a->nid - b->nid;
|
||||
}
|
||||
|
||||
IMPLEMENT_OBJ_BSEARCH_CMP_FN(ASN1_STRING_TABLE, ASN1_STRING_TABLE, table);
|
||||
|
||||
ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid)
|
||||
{
|
||||
int idx;
|
||||
ASN1_STRING_TABLE fnd;
|
||||
|
||||
#ifndef OPENSSL_NO_AUTOLOAD_CONFIG
|
||||
/* "stable" can be impacted by config, so load the config file first */
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
|
||||
#endif
|
||||
|
||||
fnd.nid = nid;
|
||||
if (stable != NULL) {
|
||||
/* Ideally, this would be done under lock */
|
||||
sk_ASN1_STRING_TABLE_sort(stable);
|
||||
idx = sk_ASN1_STRING_TABLE_find(stable, &fnd);
|
||||
if (idx >= 0)
|
||||
return sk_ASN1_STRING_TABLE_value(stable, idx);
|
||||
}
|
||||
return OBJ_bsearch_table(&fnd, tbl_standard, OSSL_NELEM(tbl_standard));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a string table pointer which can be modified: either directly from
|
||||
* table or a copy of an internal value added to the table.
|
||||
*/
|
||||
|
||||
static ASN1_STRING_TABLE *stable_get(int nid)
|
||||
{
|
||||
ASN1_STRING_TABLE *tmp, *rv;
|
||||
|
||||
/* Always need a string table so allocate one if NULL */
|
||||
if (stable == NULL) {
|
||||
stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp);
|
||||
if (stable == NULL)
|
||||
return NULL;
|
||||
}
|
||||
tmp = ASN1_STRING_TABLE_get(nid);
|
||||
if (tmp != NULL && tmp->flags & STABLE_FLAGS_MALLOC)
|
||||
return tmp;
|
||||
if ((rv = OPENSSL_zalloc(sizeof(*rv))) == NULL)
|
||||
return NULL;
|
||||
if (!sk_ASN1_STRING_TABLE_push(stable, rv)) {
|
||||
OPENSSL_free(rv);
|
||||
return NULL;
|
||||
}
|
||||
if (tmp != NULL) {
|
||||
rv->nid = tmp->nid;
|
||||
rv->minsize = tmp->minsize;
|
||||
rv->maxsize = tmp->maxsize;
|
||||
rv->mask = tmp->mask;
|
||||
rv->flags = tmp->flags | STABLE_FLAGS_MALLOC;
|
||||
} else {
|
||||
rv->nid = nid;
|
||||
rv->minsize = -1;
|
||||
rv->maxsize = -1;
|
||||
rv->flags = STABLE_FLAGS_MALLOC;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ASN1_STRING_TABLE_add(int nid,
|
||||
long minsize, long maxsize, unsigned long mask,
|
||||
unsigned long flags)
|
||||
{
|
||||
ASN1_STRING_TABLE *tmp;
|
||||
|
||||
tmp = stable_get(nid);
|
||||
if (tmp == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
return 0;
|
||||
}
|
||||
if (minsize >= 0)
|
||||
tmp->minsize = minsize;
|
||||
if (maxsize >= 0)
|
||||
tmp->maxsize = maxsize;
|
||||
if (mask)
|
||||
tmp->mask = mask;
|
||||
if (flags)
|
||||
tmp->flags = STABLE_FLAGS_MALLOC | flags;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ASN1_STRING_TABLE_cleanup(void)
|
||||
{
|
||||
STACK_OF(ASN1_STRING_TABLE) *tmp;
|
||||
|
||||
tmp = stable;
|
||||
if (tmp == NULL)
|
||||
return;
|
||||
stable = NULL;
|
||||
sk_ASN1_STRING_TABLE_pop_free(tmp, st_free);
|
||||
}
|
||||
|
||||
static void st_free(ASN1_STRING_TABLE *tbl)
|
||||
{
|
||||
if (tbl->flags & STABLE_FLAGS_MALLOC)
|
||||
OPENSSL_free(tbl);
|
||||
}
|
||||
@@ -0,0 +1,588 @@
|
||||
/*
|
||||
* Copyright 1999-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*-
|
||||
* This is an implementation of the ASN1 Time structure which is:
|
||||
* Time ::= CHOICE {
|
||||
* utcTime UTCTime,
|
||||
* generalTime GeneralizedTime }
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/ctype.h"
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1t.h>
|
||||
#include "asn1_local.h"
|
||||
|
||||
IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME)
|
||||
|
||||
IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME)
|
||||
IMPLEMENT_ASN1_DUP_FUNCTION(ASN1_TIME)
|
||||
|
||||
static int is_utc(const int year)
|
||||
{
|
||||
if (50 <= year && year <= 149)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int leap_year(const int year)
|
||||
{
|
||||
if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the day of the week and the day of the year from the year, month
|
||||
* and day. The day of the year is straightforward, the day of the week uses
|
||||
* a form of Zeller's congruence. For this months start with March and are
|
||||
* numbered 4 through 15.
|
||||
*/
|
||||
static void determine_days(struct tm *tm)
|
||||
{
|
||||
static const int ydays[12] = {
|
||||
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
|
||||
};
|
||||
int y = tm->tm_year + 1900;
|
||||
int m = tm->tm_mon;
|
||||
int d = tm->tm_mday;
|
||||
int c;
|
||||
|
||||
tm->tm_yday = ydays[m] + d - 1;
|
||||
if (m >= 2) {
|
||||
/* March and onwards can be one day further into the year */
|
||||
tm->tm_yday += leap_year(y);
|
||||
m += 2;
|
||||
} else {
|
||||
/* Treat January and February as part of the previous year */
|
||||
m += 14;
|
||||
y--;
|
||||
}
|
||||
c = y / 100;
|
||||
y %= 100;
|
||||
/* Zeller's congruence */
|
||||
tm->tm_wday = (d + (13 * m) / 5 + y + y / 4 + c / 4 + 5 * c + 6) % 7;
|
||||
}
|
||||
|
||||
int ossl_asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d)
|
||||
{
|
||||
static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 };
|
||||
static const int max[9] = { 99, 99, 12, 31, 23, 59, 59, 12, 59 };
|
||||
static const int mdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
char *a;
|
||||
int n, i, i2, l, o, min_l, strict = 0, end = 6, btz = 5, md;
|
||||
struct tm tmp;
|
||||
#if defined(CHARSET_EBCDIC)
|
||||
const char upper_z = 0x5A, num_zero = 0x30, period = 0x2E, minus = 0x2D, plus = 0x2B;
|
||||
#else
|
||||
const char upper_z = 'Z', num_zero = '0', period = '.', minus = '-', plus = '+';
|
||||
#endif
|
||||
/*
|
||||
* ASN1_STRING_FLAG_X509_TIME is used to enforce RFC 5280
|
||||
* time string format, in which:
|
||||
*
|
||||
* 1. "seconds" is a 'MUST'
|
||||
* 2. "Zulu" timezone is a 'MUST'
|
||||
* 3. "+|-" is not allowed to indicate a timezone
|
||||
*/
|
||||
if (d->type == V_ASN1_UTCTIME) {
|
||||
min_l = 13;
|
||||
if (d->flags & ASN1_STRING_FLAG_X509_TIME) {
|
||||
strict = 1;
|
||||
}
|
||||
} else if (d->type == V_ASN1_GENERALIZEDTIME) {
|
||||
end = 7;
|
||||
btz = 6;
|
||||
min_l = 15;
|
||||
if (d->flags & ASN1_STRING_FLAG_X509_TIME) {
|
||||
strict = 1;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
l = d->length;
|
||||
a = (char *)d->data;
|
||||
o = 0;
|
||||
memset(&tmp, 0, sizeof(tmp));
|
||||
|
||||
/*
|
||||
* GENERALIZEDTIME is similar to UTCTIME except the year is represented
|
||||
* as YYYY. This stuff treats everything as a two digit field so make
|
||||
* first two fields 00 to 99
|
||||
*/
|
||||
|
||||
if (l < min_l)
|
||||
goto err;
|
||||
for (i = 0; i < end; i++) {
|
||||
if (!strict && (i == btz) && ((a[o] == upper_z) || (a[o] == plus) || (a[o] == minus))) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (!ossl_ascii_isdigit(a[o]))
|
||||
goto err;
|
||||
n = a[o] - num_zero;
|
||||
/* incomplete 2-digital number */
|
||||
if (++o == l)
|
||||
goto err;
|
||||
|
||||
if (!ossl_ascii_isdigit(a[o]))
|
||||
goto err;
|
||||
n = (n * 10) + a[o] - num_zero;
|
||||
/* no more bytes to read, but we haven't seen time-zone yet */
|
||||
if (++o == l)
|
||||
goto err;
|
||||
|
||||
i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i;
|
||||
|
||||
if ((n < min[i2]) || (n > max[i2]))
|
||||
goto err;
|
||||
switch (i2) {
|
||||
case 0:
|
||||
/* UTC will never be here */
|
||||
tmp.tm_year = n * 100 - 1900;
|
||||
break;
|
||||
case 1:
|
||||
if (d->type == V_ASN1_UTCTIME)
|
||||
tmp.tm_year = n < 50 ? n + 100 : n;
|
||||
else
|
||||
tmp.tm_year += n;
|
||||
break;
|
||||
case 2:
|
||||
tmp.tm_mon = n - 1;
|
||||
break;
|
||||
case 3:
|
||||
/* check if tm_mday is valid in tm_mon */
|
||||
if (tmp.tm_mon == 1) {
|
||||
/* it's February */
|
||||
md = mdays[1] + leap_year(tmp.tm_year + 1900);
|
||||
} else {
|
||||
md = mdays[tmp.tm_mon];
|
||||
}
|
||||
if (n > md)
|
||||
goto err;
|
||||
tmp.tm_mday = n;
|
||||
determine_days(&tmp);
|
||||
break;
|
||||
case 4:
|
||||
tmp.tm_hour = n;
|
||||
break;
|
||||
case 5:
|
||||
tmp.tm_min = n;
|
||||
break;
|
||||
case 6:
|
||||
tmp.tm_sec = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Optional fractional seconds: decimal point followed by one or more
|
||||
* digits.
|
||||
*/
|
||||
if (d->type == V_ASN1_GENERALIZEDTIME && a[o] == period) {
|
||||
if (strict)
|
||||
/* RFC 5280 forbids fractional seconds */
|
||||
goto err;
|
||||
if (++o == l)
|
||||
goto err;
|
||||
i = o;
|
||||
while ((o < l) && ossl_ascii_isdigit(a[o]))
|
||||
o++;
|
||||
/* Must have at least one digit after decimal point */
|
||||
if (i == o)
|
||||
goto err;
|
||||
/* no more bytes to read, but we haven't seen time-zone yet */
|
||||
if (o == l)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* 'o' will never point to '\0' at this point, the only chance
|
||||
* 'o' can point to '\0' is either the subsequent if or the first
|
||||
* else if is true.
|
||||
*/
|
||||
if (a[o] == upper_z) {
|
||||
o++;
|
||||
} else if (!strict && ((a[o] == plus) || (a[o] == minus))) {
|
||||
int offsign = a[o] == minus ? 1 : -1;
|
||||
int offset = 0;
|
||||
|
||||
o++;
|
||||
/*
|
||||
* if not equal, no need to do subsequent checks
|
||||
* since the following for-loop will add 'o' by 4
|
||||
* and the final return statement will check if 'l'
|
||||
* and 'o' are equal.
|
||||
*/
|
||||
if (o + 4 != l)
|
||||
goto err;
|
||||
for (i = end; i < end + 2; i++) {
|
||||
if (!ossl_ascii_isdigit(a[o]))
|
||||
goto err;
|
||||
n = a[o] - num_zero;
|
||||
o++;
|
||||
if (!ossl_ascii_isdigit(a[o]))
|
||||
goto err;
|
||||
n = (n * 10) + a[o] - num_zero;
|
||||
i2 = (d->type == V_ASN1_UTCTIME) ? i + 1 : i;
|
||||
if ((n < min[i2]) || (n > max[i2]))
|
||||
goto err;
|
||||
/* if tm is NULL, no need to adjust */
|
||||
if (tm != NULL) {
|
||||
if (i == end)
|
||||
offset = n * 3600;
|
||||
else if (i == end + 1)
|
||||
offset += n * 60;
|
||||
}
|
||||
o++;
|
||||
}
|
||||
if (offset && !OPENSSL_gmtime_adj(&tmp, 0, offset * offsign))
|
||||
goto err;
|
||||
} else {
|
||||
/* not Z, or not +/- in non-strict mode */
|
||||
goto err;
|
||||
}
|
||||
if (o == l) {
|
||||
/* success, check if tm should be filled */
|
||||
if (tm != NULL)
|
||||
*tm = tmp;
|
||||
return 1;
|
||||
}
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
ASN1_TIME *ossl_asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type)
|
||||
{
|
||||
char* p;
|
||||
ASN1_TIME *tmps = NULL;
|
||||
const size_t len = 20;
|
||||
|
||||
if (type == V_ASN1_UNDEF) {
|
||||
if (is_utc(ts->tm_year))
|
||||
type = V_ASN1_UTCTIME;
|
||||
else
|
||||
type = V_ASN1_GENERALIZEDTIME;
|
||||
} else if (type == V_ASN1_UTCTIME) {
|
||||
if (!is_utc(ts->tm_year))
|
||||
goto err;
|
||||
} else if (type != V_ASN1_GENERALIZEDTIME) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (s == NULL)
|
||||
tmps = ASN1_STRING_new();
|
||||
else
|
||||
tmps = s;
|
||||
if (tmps == NULL)
|
||||
return NULL;
|
||||
|
||||
if (!ASN1_STRING_set(tmps, NULL, len))
|
||||
goto err;
|
||||
|
||||
tmps->type = type;
|
||||
p = (char*)tmps->data;
|
||||
|
||||
if (ts->tm_mon > INT_MAX - 1)
|
||||
goto err;
|
||||
|
||||
if (type == V_ASN1_GENERALIZEDTIME) {
|
||||
if (ts->tm_year > INT_MAX - 1900)
|
||||
goto err;
|
||||
tmps->length = BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ",
|
||||
ts->tm_year + 1900, ts->tm_mon + 1,
|
||||
ts->tm_mday, ts->tm_hour, ts->tm_min,
|
||||
ts->tm_sec);
|
||||
} else {
|
||||
tmps->length = BIO_snprintf(p, len, "%02d%02d%02d%02d%02d%02dZ",
|
||||
ts->tm_year % 100, ts->tm_mon + 1,
|
||||
ts->tm_mday, ts->tm_hour, ts->tm_min,
|
||||
ts->tm_sec);
|
||||
}
|
||||
|
||||
#ifdef CHARSET_EBCDIC
|
||||
ebcdic2ascii(tmps->data, tmps->data, tmps->length);
|
||||
#endif
|
||||
return tmps;
|
||||
err:
|
||||
if (tmps != s)
|
||||
ASN1_STRING_free(tmps);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t)
|
||||
{
|
||||
return ASN1_TIME_adj(s, t, 0, 0);
|
||||
}
|
||||
|
||||
ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t,
|
||||
int offset_day, long offset_sec)
|
||||
{
|
||||
struct tm *ts;
|
||||
struct tm data;
|
||||
|
||||
ts = OPENSSL_gmtime(&t, &data);
|
||||
if (ts == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ERROR_GETTING_TIME);
|
||||
return NULL;
|
||||
}
|
||||
if (offset_day || offset_sec) {
|
||||
if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
|
||||
return NULL;
|
||||
}
|
||||
return ossl_asn1_time_from_tm(s, ts, V_ASN1_UNDEF);
|
||||
}
|
||||
|
||||
int ASN1_TIME_check(const ASN1_TIME *t)
|
||||
{
|
||||
if (t->type == V_ASN1_GENERALIZEDTIME)
|
||||
return ASN1_GENERALIZEDTIME_check(t);
|
||||
else if (t->type == V_ASN1_UTCTIME)
|
||||
return ASN1_UTCTIME_check(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Convert an ASN1_TIME structure to GeneralizedTime */
|
||||
ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(const ASN1_TIME *t,
|
||||
ASN1_GENERALIZEDTIME **out)
|
||||
{
|
||||
ASN1_GENERALIZEDTIME *ret = NULL;
|
||||
struct tm tm;
|
||||
|
||||
if (!ASN1_TIME_to_tm(t, &tm))
|
||||
return NULL;
|
||||
|
||||
if (out != NULL)
|
||||
ret = *out;
|
||||
|
||||
ret = ossl_asn1_time_from_tm(ret, &tm, V_ASN1_GENERALIZEDTIME);
|
||||
|
||||
if (out != NULL && ret != NULL)
|
||||
*out = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ASN1_TIME_set_string(ASN1_TIME *s, const char *str)
|
||||
{
|
||||
/* Try UTC, if that fails, try GENERALIZED */
|
||||
if (ASN1_UTCTIME_set_string(s, str))
|
||||
return 1;
|
||||
return ASN1_GENERALIZEDTIME_set_string(s, str);
|
||||
}
|
||||
|
||||
int ASN1_TIME_set_string_X509(ASN1_TIME *s, const char *str)
|
||||
{
|
||||
ASN1_TIME t;
|
||||
struct tm tm;
|
||||
int rv = 0;
|
||||
|
||||
t.length = strlen(str);
|
||||
t.data = (unsigned char *)str;
|
||||
t.flags = ASN1_STRING_FLAG_X509_TIME;
|
||||
|
||||
t.type = V_ASN1_UTCTIME;
|
||||
|
||||
if (!ASN1_TIME_check(&t)) {
|
||||
t.type = V_ASN1_GENERALIZEDTIME;
|
||||
if (!ASN1_TIME_check(&t))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Per RFC 5280 (section 4.1.2.5.), the valid input time
|
||||
* strings should be encoded with the following rules:
|
||||
*
|
||||
* 1. UTC: YYMMDDHHMMSSZ, if YY < 50 (20YY) --> UTC: YYMMDDHHMMSSZ
|
||||
* 2. UTC: YYMMDDHHMMSSZ, if YY >= 50 (19YY) --> UTC: YYMMDDHHMMSSZ
|
||||
* 3. G'd: YYYYMMDDHHMMSSZ, if YYYY >= 2050 --> G'd: YYYYMMDDHHMMSSZ
|
||||
* 4. G'd: YYYYMMDDHHMMSSZ, if YYYY < 2050 --> UTC: YYMMDDHHMMSSZ
|
||||
*
|
||||
* Only strings of the 4th rule should be reformatted, but since a
|
||||
* UTC can only present [1950, 2050), so if the given time string
|
||||
* is less than 1950 (e.g. 19230419000000Z), we do nothing...
|
||||
*/
|
||||
|
||||
if (s != NULL && t.type == V_ASN1_GENERALIZEDTIME) {
|
||||
if (!ossl_asn1_time_to_tm(&tm, &t))
|
||||
goto out;
|
||||
if (is_utc(tm.tm_year)) {
|
||||
t.length -= 2;
|
||||
/*
|
||||
* it's OK to let original t.data go since that's assigned
|
||||
* to a piece of memory allocated outside of this function.
|
||||
* new t.data would be freed after ASN1_STRING_copy is done.
|
||||
*/
|
||||
t.data = OPENSSL_zalloc(t.length + 1);
|
||||
if (t.data == NULL)
|
||||
goto out;
|
||||
memcpy(t.data, str + 2, t.length);
|
||||
t.type = V_ASN1_UTCTIME;
|
||||
}
|
||||
}
|
||||
|
||||
if (s == NULL || ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t))
|
||||
rv = 1;
|
||||
|
||||
if (t.data != (unsigned char *)str)
|
||||
OPENSSL_free(t.data);
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ASN1_TIME_to_tm(const ASN1_TIME *s, struct tm *tm)
|
||||
{
|
||||
if (s == NULL) {
|
||||
time_t now_t;
|
||||
|
||||
time(&now_t);
|
||||
memset(tm, 0, sizeof(*tm));
|
||||
if (OPENSSL_gmtime(&now_t, tm) != NULL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ossl_asn1_time_to_tm(tm, s);
|
||||
}
|
||||
|
||||
int ASN1_TIME_diff(int *pday, int *psec,
|
||||
const ASN1_TIME *from, const ASN1_TIME *to)
|
||||
{
|
||||
struct tm tm_from, tm_to;
|
||||
|
||||
if (!ASN1_TIME_to_tm(from, &tm_from))
|
||||
return 0;
|
||||
if (!ASN1_TIME_to_tm(to, &tm_to))
|
||||
return 0;
|
||||
return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to);
|
||||
}
|
||||
|
||||
static const char _asn1_mon[12][4] = {
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
/* prints the time with the default date format (RFC 822) */
|
||||
int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm)
|
||||
{
|
||||
return ASN1_TIME_print_ex(bp, tm, ASN1_DTFLGS_RFC822);
|
||||
}
|
||||
|
||||
/* returns 1 on success, 0 on BIO write error or parse failure */
|
||||
int ASN1_TIME_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags)
|
||||
{
|
||||
return ossl_asn1_time_print_ex(bp, tm, flags) > 0;
|
||||
}
|
||||
|
||||
|
||||
/* prints the time with the date format of ISO 8601 */
|
||||
/* returns 0 on BIO write error, else -1 in case of parse failure, else 1 */
|
||||
int ossl_asn1_time_print_ex(BIO *bp, const ASN1_TIME *tm, unsigned long flags)
|
||||
{
|
||||
char *v;
|
||||
int l;
|
||||
struct tm stm;
|
||||
const char period = 0x2E;
|
||||
|
||||
/* ossl_asn1_time_to_tm will check the time type */
|
||||
if (!ossl_asn1_time_to_tm(&stm, tm))
|
||||
return BIO_write(bp, "Bad time value", 14) ? -1 : 0;
|
||||
|
||||
l = tm->length;
|
||||
v = (char *)tm->data;
|
||||
|
||||
if (tm->type == V_ASN1_GENERALIZEDTIME) {
|
||||
char *f = NULL;
|
||||
int f_len = 0;
|
||||
|
||||
/*
|
||||
* Try to parse fractional seconds. '14' is the place of
|
||||
* 'fraction point' in a GeneralizedTime string.
|
||||
*/
|
||||
if (tm->length > 15 && v[14] == period) {
|
||||
/* exclude the . itself */
|
||||
f = &v[15];
|
||||
f_len = 0;
|
||||
while (15 + f_len < l && ossl_ascii_isdigit(f[f_len]))
|
||||
++f_len;
|
||||
}
|
||||
|
||||
if (f_len > 0) {
|
||||
if ((flags & ASN1_DTFLGS_TYPE_MASK) == ASN1_DTFLGS_ISO8601) {
|
||||
return BIO_printf(bp, "%4d-%02d-%02d %02d:%02d:%02d.%.*sZ",
|
||||
stm.tm_year + 1900, stm.tm_mon + 1,
|
||||
stm.tm_mday, stm.tm_hour,
|
||||
stm.tm_min, stm.tm_sec, f_len, f) > 0;
|
||||
} else {
|
||||
return BIO_printf(bp, "%s %2d %02d:%02d:%02d.%.*s %d GMT",
|
||||
_asn1_mon[stm.tm_mon], stm.tm_mday, stm.tm_hour,
|
||||
stm.tm_min, stm.tm_sec, f_len, f,
|
||||
stm.tm_year + 1900) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((flags & ASN1_DTFLGS_TYPE_MASK) == ASN1_DTFLGS_ISO8601) {
|
||||
return BIO_printf(bp, "%4d-%02d-%02d %02d:%02d:%02dZ",
|
||||
stm.tm_year + 1900, stm.tm_mon + 1,
|
||||
stm.tm_mday, stm.tm_hour,
|
||||
stm.tm_min, stm.tm_sec) > 0;
|
||||
} else {
|
||||
return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d GMT",
|
||||
_asn1_mon[stm.tm_mon], stm.tm_mday, stm.tm_hour,
|
||||
stm.tm_min, stm.tm_sec, stm.tm_year + 1900) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ASN1_TIME_cmp_time_t(const ASN1_TIME *s, time_t t)
|
||||
{
|
||||
struct tm stm, ttm;
|
||||
int day, sec;
|
||||
|
||||
if (!ASN1_TIME_to_tm(s, &stm))
|
||||
return -2;
|
||||
|
||||
if (!OPENSSL_gmtime(&t, &ttm))
|
||||
return -2;
|
||||
|
||||
if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm))
|
||||
return -2;
|
||||
|
||||
if (day > 0 || sec > 0)
|
||||
return 1;
|
||||
if (day < 0 || sec < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ASN1_TIME_normalize(ASN1_TIME *t)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
if (t == NULL || !ASN1_TIME_to_tm(t, &tm))
|
||||
return 0;
|
||||
|
||||
return ossl_asn1_time_from_tm(t, &tm, V_ASN1_UNDEF) != NULL;
|
||||
}
|
||||
|
||||
int ASN1_TIME_compare(const ASN1_TIME *a, const ASN1_TIME *b)
|
||||
{
|
||||
int day, sec;
|
||||
|
||||
if (!ASN1_TIME_diff(&day, &sec, b, a))
|
||||
return -2;
|
||||
if (day > 0 || sec > 0)
|
||||
return 1;
|
||||
if (day < 0 || sec < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/objects.h>
|
||||
#include "asn1_local.h"
|
||||
|
||||
int ASN1_TYPE_get(const ASN1_TYPE *a)
|
||||
{
|
||||
if (a->type == V_ASN1_BOOLEAN
|
||||
|| a->type == V_ASN1_NULL
|
||||
|| a->value.ptr != NULL)
|
||||
return a->type;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value)
|
||||
{
|
||||
if (a->type != V_ASN1_BOOLEAN
|
||||
&& a->type != V_ASN1_NULL
|
||||
&& a->value.ptr != NULL) {
|
||||
ASN1_TYPE **tmp_a = &a;
|
||||
ossl_asn1_primitive_free((ASN1_VALUE **)tmp_a, NULL, 0);
|
||||
}
|
||||
a->type = type;
|
||||
if (type == V_ASN1_BOOLEAN)
|
||||
a->value.boolean = value ? 0xff : 0;
|
||||
else
|
||||
a->value.ptr = value;
|
||||
}
|
||||
|
||||
int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value)
|
||||
{
|
||||
if (!value || (type == V_ASN1_BOOLEAN)) {
|
||||
void *p = (void *)value;
|
||||
ASN1_TYPE_set(a, type, p);
|
||||
} else if (type == V_ASN1_OBJECT) {
|
||||
ASN1_OBJECT *odup;
|
||||
odup = OBJ_dup(value);
|
||||
if (!odup)
|
||||
return 0;
|
||||
ASN1_TYPE_set(a, type, odup);
|
||||
} else {
|
||||
ASN1_STRING *sdup;
|
||||
sdup = ASN1_STRING_dup(value);
|
||||
if (!sdup)
|
||||
return 0;
|
||||
ASN1_TYPE_set(a, type, sdup);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Returns 0 if they are equal, != 0 otherwise. */
|
||||
int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b)
|
||||
{
|
||||
int result = -1;
|
||||
|
||||
if (!a || !b || a->type != b->type)
|
||||
return -1;
|
||||
|
||||
switch (a->type) {
|
||||
case V_ASN1_OBJECT:
|
||||
result = OBJ_cmp(a->value.object, b->value.object);
|
||||
break;
|
||||
case V_ASN1_BOOLEAN:
|
||||
result = a->value.boolean - b->value.boolean;
|
||||
break;
|
||||
case V_ASN1_NULL:
|
||||
result = 0; /* They do not have content. */
|
||||
break;
|
||||
case V_ASN1_INTEGER:
|
||||
case V_ASN1_ENUMERATED:
|
||||
case V_ASN1_BIT_STRING:
|
||||
case V_ASN1_OCTET_STRING:
|
||||
case V_ASN1_SEQUENCE:
|
||||
case V_ASN1_SET:
|
||||
case V_ASN1_NUMERICSTRING:
|
||||
case V_ASN1_PRINTABLESTRING:
|
||||
case V_ASN1_T61STRING:
|
||||
case V_ASN1_VIDEOTEXSTRING:
|
||||
case V_ASN1_IA5STRING:
|
||||
case V_ASN1_UTCTIME:
|
||||
case V_ASN1_GENERALIZEDTIME:
|
||||
case V_ASN1_GRAPHICSTRING:
|
||||
case V_ASN1_VISIBLESTRING:
|
||||
case V_ASN1_GENERALSTRING:
|
||||
case V_ASN1_UNIVERSALSTRING:
|
||||
case V_ASN1_BMPSTRING:
|
||||
case V_ASN1_UTF8STRING:
|
||||
case V_ASN1_OTHER:
|
||||
default:
|
||||
result = ASN1_STRING_cmp((ASN1_STRING *)a->value.ptr,
|
||||
(ASN1_STRING *)b->value.ptr);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ASN1_TYPE *ASN1_TYPE_pack_sequence(const ASN1_ITEM *it, void *s, ASN1_TYPE **t)
|
||||
{
|
||||
ASN1_OCTET_STRING *oct;
|
||||
ASN1_TYPE *rt;
|
||||
|
||||
oct = ASN1_item_pack(s, it, NULL);
|
||||
if (oct == NULL)
|
||||
return NULL;
|
||||
|
||||
if (t && *t) {
|
||||
rt = *t;
|
||||
} else {
|
||||
rt = ASN1_TYPE_new();
|
||||
if (rt == NULL) {
|
||||
ASN1_OCTET_STRING_free(oct);
|
||||
return NULL;
|
||||
}
|
||||
if (t)
|
||||
*t = rt;
|
||||
}
|
||||
ASN1_TYPE_set(rt, V_ASN1_SEQUENCE, oct);
|
||||
return rt;
|
||||
}
|
||||
|
||||
void *ASN1_TYPE_unpack_sequence(const ASN1_ITEM *it, const ASN1_TYPE *t)
|
||||
{
|
||||
if (t == NULL || t->type != V_ASN1_SEQUENCE || t->value.sequence == NULL)
|
||||
return NULL;
|
||||
return ASN1_item_unpack(t->value.sequence, it);
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
#include "asn1_local.h"
|
||||
#include <openssl/asn1t.h>
|
||||
|
||||
IMPLEMENT_ASN1_DUP_FUNCTION(ASN1_UTCTIME)
|
||||
|
||||
/* This is the primary function used to parse ASN1_UTCTIME */
|
||||
int ossl_asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
|
||||
{
|
||||
/* wrapper around ossl_asn1_time_to_tm */
|
||||
if (d->type != V_ASN1_UTCTIME)
|
||||
return 0;
|
||||
return ossl_asn1_time_to_tm(tm, d);
|
||||
}
|
||||
|
||||
int ASN1_UTCTIME_check(const ASN1_UTCTIME *d)
|
||||
{
|
||||
return ossl_asn1_utctime_to_tm(NULL, d);
|
||||
}
|
||||
|
||||
/* Sets the string via simple copy without cleaning it up */
|
||||
int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str)
|
||||
{
|
||||
ASN1_UTCTIME t;
|
||||
|
||||
t.type = V_ASN1_UTCTIME;
|
||||
t.length = strlen(str);
|
||||
t.data = (unsigned char *)str;
|
||||
t.flags = 0;
|
||||
|
||||
if (!ASN1_UTCTIME_check(&t))
|
||||
return 0;
|
||||
|
||||
if (s != NULL && !ASN1_STRING_copy(s, &t))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t)
|
||||
{
|
||||
return ASN1_UTCTIME_adj(s, t, 0, 0);
|
||||
}
|
||||
|
||||
ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t,
|
||||
int offset_day, long offset_sec)
|
||||
{
|
||||
struct tm *ts;
|
||||
struct tm data;
|
||||
|
||||
ts = OPENSSL_gmtime(&t, &data);
|
||||
if (ts == NULL)
|
||||
return NULL;
|
||||
|
||||
if (offset_day || offset_sec) {
|
||||
if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ossl_asn1_time_from_tm(s, ts, V_ASN1_UTCTIME);
|
||||
}
|
||||
|
||||
int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t)
|
||||
{
|
||||
struct tm stm, ttm;
|
||||
int day, sec;
|
||||
|
||||
if (!ossl_asn1_utctime_to_tm(&stm, s))
|
||||
return -2;
|
||||
|
||||
if (OPENSSL_gmtime(&t, &ttm) == NULL)
|
||||
return -2;
|
||||
|
||||
if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm))
|
||||
return -2;
|
||||
|
||||
if (day > 0 || sec > 0)
|
||||
return 1;
|
||||
if (day < 0 || sec < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
|
||||
{
|
||||
if (tm->type != V_ASN1_UTCTIME)
|
||||
return 0;
|
||||
return ASN1_TIME_print(bp, tm);
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "internal/unicode.h"
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
/* UTF8 utilities */
|
||||
|
||||
/*-
|
||||
* This parses a UTF8 string one character at a time. It is passed a pointer
|
||||
* to the string and the length of the string. It sets 'value' to the value of
|
||||
* the current character. It returns the number of characters read or a
|
||||
* negative error code:
|
||||
* -1 = string too short
|
||||
* -2 = illegal character
|
||||
* -3 = subsequent characters not of the form 10xxxxxx
|
||||
* -4 = character encoded incorrectly (not minimal length).
|
||||
*/
|
||||
|
||||
int UTF8_getc(const unsigned char *str, int len, unsigned long *val)
|
||||
{
|
||||
const unsigned char *p;
|
||||
unsigned long value;
|
||||
int ret;
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
p = str;
|
||||
|
||||
/* Check syntax and work out the encoded value (if correct) */
|
||||
if ((*p & 0x80) == 0) {
|
||||
value = *p++ & 0x7f;
|
||||
ret = 1;
|
||||
} else if ((*p & 0xe0) == 0xc0) {
|
||||
if (len < 2)
|
||||
return -1;
|
||||
if ((p[1] & 0xc0) != 0x80)
|
||||
return -3;
|
||||
value = (*p++ & 0x1f) << 6;
|
||||
value |= *p++ & 0x3f;
|
||||
if (value < 0x80)
|
||||
return -4;
|
||||
ret = 2;
|
||||
} else if ((*p & 0xf0) == 0xe0) {
|
||||
if (len < 3)
|
||||
return -1;
|
||||
if (((p[1] & 0xc0) != 0x80)
|
||||
|| ((p[2] & 0xc0) != 0x80))
|
||||
return -3;
|
||||
value = (*p++ & 0xf) << 12;
|
||||
value |= (*p++ & 0x3f) << 6;
|
||||
value |= *p++ & 0x3f;
|
||||
if (value < 0x800)
|
||||
return -4;
|
||||
if (is_unicode_surrogate(value))
|
||||
return -2;
|
||||
ret = 3;
|
||||
} else if ((*p & 0xf8) == 0xf0) {
|
||||
if (len < 4)
|
||||
return -1;
|
||||
if (((p[1] & 0xc0) != 0x80)
|
||||
|| ((p[2] & 0xc0) != 0x80)
|
||||
|| ((p[3] & 0xc0) != 0x80))
|
||||
return -3;
|
||||
value = ((unsigned long)(*p++ & 0x7)) << 18;
|
||||
value |= (*p++ & 0x3f) << 12;
|
||||
value |= (*p++ & 0x3f) << 6;
|
||||
value |= *p++ & 0x3f;
|
||||
if (value < 0x10000)
|
||||
return -4;
|
||||
ret = 4;
|
||||
} else
|
||||
return -2;
|
||||
*val = value;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This takes a character 'value' and writes the UTF8 encoded value in 'str'
|
||||
* where 'str' is a buffer containing 'len' characters. Returns the number of
|
||||
* characters written, -1 if 'len' is too small or -2 if 'value' is out of
|
||||
* range. 'str' can be set to NULL in which case it just returns the number of
|
||||
* characters. It will need at most 4 characters.
|
||||
*/
|
||||
|
||||
int UTF8_putc(unsigned char *str, int len, unsigned long value)
|
||||
{
|
||||
if (!str)
|
||||
len = 4; /* Maximum we will need */
|
||||
else if (len <= 0)
|
||||
return -1;
|
||||
if (value < 0x80) {
|
||||
if (str)
|
||||
*str = (unsigned char)value;
|
||||
return 1;
|
||||
}
|
||||
if (value < 0x800) {
|
||||
if (len < 2)
|
||||
return -1;
|
||||
if (str) {
|
||||
*str++ = (unsigned char)(((value >> 6) & 0x1f) | 0xc0);
|
||||
*str = (unsigned char)((value & 0x3f) | 0x80);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
if (value < 0x10000) {
|
||||
if (is_unicode_surrogate(value))
|
||||
return -2;
|
||||
if (len < 3)
|
||||
return -1;
|
||||
if (str) {
|
||||
*str++ = (unsigned char)(((value >> 12) & 0xf) | 0xe0);
|
||||
*str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
|
||||
*str = (unsigned char)((value & 0x3f) | 0x80);
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
if (value < UNICODE_LIMIT) {
|
||||
if (len < 4)
|
||||
return -1;
|
||||
if (str) {
|
||||
*str++ = (unsigned char)(((value >> 18) & 0x7) | 0xf0);
|
||||
*str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80);
|
||||
*str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80);
|
||||
*str = (unsigned char)((value & 0x3f) | 0x80);
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
return -2;
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/evp.h>
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "crypto/rsa.h"
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
|
||||
int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *a, ASN1_BIT_STRING *signature,
|
||||
char *data, EVP_PKEY *pkey)
|
||||
{
|
||||
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
|
||||
const EVP_MD *type;
|
||||
unsigned char *p, *buf_in = NULL;
|
||||
int ret = -1, i, inl;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
i = OBJ_obj2nid(a->algorithm);
|
||||
type = EVP_get_digestbyname(OBJ_nid2sn(i));
|
||||
if (type == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT);
|
||||
goto err;
|
||||
}
|
||||
|
||||
inl = i2d(data, NULL);
|
||||
if (inl <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
buf_in = OPENSSL_malloc((unsigned int)inl);
|
||||
if (buf_in == NULL)
|
||||
goto err;
|
||||
p = buf_in;
|
||||
|
||||
i2d(data, &p);
|
||||
ret = EVP_VerifyInit_ex(ctx, type, NULL)
|
||||
&& EVP_VerifyUpdate(ctx, (unsigned char *)buf_in, inl);
|
||||
|
||||
OPENSSL_clear_free(buf_in, (unsigned int)inl);
|
||||
|
||||
if (!ret) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
ret = -1;
|
||||
|
||||
if (EVP_VerifyFinal(ctx, (unsigned char *)signature->data,
|
||||
(unsigned int)signature->length, pkey) <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
ret = 0;
|
||||
goto err;
|
||||
}
|
||||
ret = 1;
|
||||
err:
|
||||
EVP_MD_CTX_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int ASN1_item_verify(const ASN1_ITEM *it, const X509_ALGOR *alg,
|
||||
const ASN1_BIT_STRING *signature, const void *data,
|
||||
EVP_PKEY *pkey)
|
||||
{
|
||||
return ASN1_item_verify_ex(it, alg, signature, data, NULL, pkey, NULL, NULL);
|
||||
}
|
||||
|
||||
int ASN1_item_verify_ex(const ASN1_ITEM *it, const X509_ALGOR *alg,
|
||||
const ASN1_BIT_STRING *signature, const void *data,
|
||||
const ASN1_OCTET_STRING *id, EVP_PKEY *pkey,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
EVP_MD_CTX *ctx;
|
||||
int rv = -1;
|
||||
|
||||
if ((ctx = evp_md_ctx_new_ex(pkey, id, libctx, propq)) != NULL) {
|
||||
rv = ASN1_item_verify_ctx(it, alg, signature, data, ctx);
|
||||
EVP_PKEY_CTX_free(EVP_MD_CTX_get_pkey_ctx(ctx));
|
||||
EVP_MD_CTX_free(ctx);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ASN1_item_verify_ctx(const ASN1_ITEM *it, const X509_ALGOR *alg,
|
||||
const ASN1_BIT_STRING *signature, const void *data,
|
||||
EVP_MD_CTX *ctx)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
unsigned char *buf_in = NULL;
|
||||
int ret = -1, inl = 0;
|
||||
int mdnid, pknid;
|
||||
size_t inll = 0;
|
||||
|
||||
pkey = EVP_PKEY_CTX_get0_pkey(EVP_MD_CTX_get_pkey_ctx(ctx));
|
||||
|
||||
if (pkey == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert signature OID into digest and public key OIDs */
|
||||
if (!OBJ_find_sigid_algs(OBJ_obj2nid(alg->algorithm), &mdnid, &pknid)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mdnid == NID_undef && evp_pkey_is_legacy(pkey)) {
|
||||
if (pkey->ameth == NULL || pkey->ameth->item_verify == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
|
||||
goto err;
|
||||
}
|
||||
ret = pkey->ameth->item_verify(ctx, it, data, alg, signature, pkey);
|
||||
/*
|
||||
* Return values meaning:
|
||||
* <=0: error.
|
||||
* 1: method does everything.
|
||||
* 2: carry on as normal, method has called EVP_DigestVerifyInit()
|
||||
*/
|
||||
if (ret <= 0)
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
if (ret <= 1)
|
||||
goto err;
|
||||
} else {
|
||||
const EVP_MD *type = NULL;
|
||||
|
||||
/*
|
||||
* We don't yet have the ability for providers to be able to handle
|
||||
* X509_ALGOR style parameters. Fortunately the only one that needs this
|
||||
* so far is RSA-PSS, so we just special case this for now. In some
|
||||
* future version of OpenSSL we should push this to the provider.
|
||||
*/
|
||||
if (mdnid == NID_undef && pknid == EVP_PKEY_RSA_PSS) {
|
||||
if (!EVP_PKEY_is_a(pkey, "RSA") && !EVP_PKEY_is_a(pkey, "RSA-PSS")) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
|
||||
goto err;
|
||||
}
|
||||
/* This function also calls EVP_DigestVerifyInit */
|
||||
if (ossl_rsa_pss_to_ctx(ctx, NULL, alg, pkey) <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
/* Check public key OID matches public key type */
|
||||
if (!EVP_PKEY_is_a(pkey, OBJ_nid2sn(pknid))) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mdnid != NID_undef) {
|
||||
type = EVP_get_digestbynid(mdnid);
|
||||
if (type == NULL) {
|
||||
ERR_raise_data(ERR_LIB_ASN1,
|
||||
ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM,
|
||||
"nid=0x%x", mdnid);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that some algorithms (notably Ed25519 and Ed448) may allow
|
||||
* a NULL digest value.
|
||||
*/
|
||||
if (!EVP_DigestVerifyInit(ctx, NULL, type, NULL, pkey)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
ret = 0;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inl = ASN1_item_i2d(data, &buf_in, it);
|
||||
if (inl <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_INTERNAL_ERROR);
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
if (buf_in == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
inll = inl;
|
||||
|
||||
ret = EVP_DigestVerify(ctx, signature->data, (size_t)signature->length,
|
||||
buf_in, inl);
|
||||
if (ret <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
ret = 1;
|
||||
err:
|
||||
OPENSSL_clear_free(buf_in, inll);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* We need to use some engine deprecated APIs */
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include "internal/cryptlib.h"
|
||||
#include <stdio.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/engine.h>
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/evp.h"
|
||||
|
||||
#include "standard_methods.h"
|
||||
|
||||
typedef int sk_cmp_fn_type(const char *const *a, const char *const *b);
|
||||
static STACK_OF(EVP_PKEY_ASN1_METHOD) *app_methods = NULL;
|
||||
|
||||
DECLARE_OBJ_BSEARCH_CMP_FN(const EVP_PKEY_ASN1_METHOD *,
|
||||
const EVP_PKEY_ASN1_METHOD *, ameth);
|
||||
|
||||
static int ameth_cmp(const EVP_PKEY_ASN1_METHOD *const *a,
|
||||
const EVP_PKEY_ASN1_METHOD *const *b)
|
||||
{
|
||||
return ((*a)->pkey_id - (*b)->pkey_id);
|
||||
}
|
||||
|
||||
IMPLEMENT_OBJ_BSEARCH_CMP_FN(const EVP_PKEY_ASN1_METHOD *,
|
||||
const EVP_PKEY_ASN1_METHOD *, ameth);
|
||||
|
||||
int EVP_PKEY_asn1_get_count(void)
|
||||
{
|
||||
int num = OSSL_NELEM(standard_methods);
|
||||
if (app_methods)
|
||||
num += sk_EVP_PKEY_ASN1_METHOD_num(app_methods);
|
||||
return num;
|
||||
}
|
||||
|
||||
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_get0(int idx)
|
||||
{
|
||||
int num = OSSL_NELEM(standard_methods);
|
||||
if (idx < 0)
|
||||
return NULL;
|
||||
if (idx < num)
|
||||
return standard_methods[idx];
|
||||
idx -= num;
|
||||
return sk_EVP_PKEY_ASN1_METHOD_value(app_methods, idx);
|
||||
}
|
||||
|
||||
static const EVP_PKEY_ASN1_METHOD *pkey_asn1_find(int type)
|
||||
{
|
||||
EVP_PKEY_ASN1_METHOD tmp;
|
||||
const EVP_PKEY_ASN1_METHOD *t = &tmp, **ret;
|
||||
|
||||
tmp.pkey_id = type;
|
||||
if (app_methods) {
|
||||
int idx;
|
||||
idx = sk_EVP_PKEY_ASN1_METHOD_find(app_methods, &tmp);
|
||||
if (idx >= 0)
|
||||
return sk_EVP_PKEY_ASN1_METHOD_value(app_methods, idx);
|
||||
}
|
||||
ret = OBJ_bsearch_ameth(&t, standard_methods, OSSL_NELEM(standard_methods));
|
||||
if (ret == NULL || *ret == NULL)
|
||||
return NULL;
|
||||
return *ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find an implementation of an ASN1 algorithm. If 'pe' is not NULL also
|
||||
* search through engines and set *pe to a functional reference to the engine
|
||||
* implementing 'type' or NULL if no engine implements it.
|
||||
*/
|
||||
|
||||
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pe, int type)
|
||||
{
|
||||
const EVP_PKEY_ASN1_METHOD *t;
|
||||
|
||||
for (;;) {
|
||||
t = pkey_asn1_find(type);
|
||||
if (!t || !(t->pkey_flags & ASN1_PKEY_ALIAS))
|
||||
break;
|
||||
type = t->pkey_base_id;
|
||||
}
|
||||
if (pe) {
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE *e;
|
||||
/* type will contain the final unaliased type */
|
||||
e = ENGINE_get_pkey_asn1_meth_engine(type);
|
||||
if (e) {
|
||||
*pe = e;
|
||||
return ENGINE_get_pkey_asn1_meth(e, type);
|
||||
}
|
||||
#endif
|
||||
*pe = NULL;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pe,
|
||||
const char *str, int len)
|
||||
{
|
||||
int i;
|
||||
const EVP_PKEY_ASN1_METHOD *ameth = NULL;
|
||||
|
||||
if (len == -1)
|
||||
len = strlen(str);
|
||||
if (pe) {
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE *e;
|
||||
ameth = ENGINE_pkey_asn1_find_str(&e, str, len);
|
||||
if (ameth) {
|
||||
/*
|
||||
* Convert structural into functional reference
|
||||
*/
|
||||
if (!ENGINE_init(e))
|
||||
ameth = NULL;
|
||||
ENGINE_free(e);
|
||||
*pe = e;
|
||||
return ameth;
|
||||
}
|
||||
#endif
|
||||
*pe = NULL;
|
||||
}
|
||||
for (i = EVP_PKEY_asn1_get_count(); i-- > 0; ) {
|
||||
ameth = EVP_PKEY_asn1_get0(i);
|
||||
if (ameth->pkey_flags & ASN1_PKEY_ALIAS)
|
||||
continue;
|
||||
if ((int)strlen(ameth->pem_str) == len
|
||||
&& OPENSSL_strncasecmp(ameth->pem_str, str, len) == 0)
|
||||
return ameth;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int EVP_PKEY_asn1_add0(const EVP_PKEY_ASN1_METHOD *ameth)
|
||||
{
|
||||
EVP_PKEY_ASN1_METHOD tmp = { 0, };
|
||||
|
||||
/*
|
||||
* One of the following must be true:
|
||||
*
|
||||
* pem_str == NULL AND ASN1_PKEY_ALIAS is set
|
||||
* pem_str != NULL AND ASN1_PKEY_ALIAS is clear
|
||||
*
|
||||
* Anything else is an error and may lead to a corrupt ASN1 method table
|
||||
*/
|
||||
if (!((ameth->pem_str == NULL
|
||||
&& (ameth->pkey_flags & ASN1_PKEY_ALIAS) != 0)
|
||||
|| (ameth->pem_str != NULL
|
||||
&& (ameth->pkey_flags & ASN1_PKEY_ALIAS) == 0))) {
|
||||
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (app_methods == NULL) {
|
||||
app_methods = sk_EVP_PKEY_ASN1_METHOD_new(ameth_cmp);
|
||||
if (app_methods == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp.pkey_id = ameth->pkey_id;
|
||||
if (sk_EVP_PKEY_ASN1_METHOD_find(app_methods, &tmp) >= 0) {
|
||||
ERR_raise(ERR_LIB_EVP,
|
||||
EVP_R_PKEY_APPLICATION_ASN1_METHOD_ALREADY_REGISTERED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sk_EVP_PKEY_ASN1_METHOD_push(app_methods, ameth))
|
||||
return 0;
|
||||
sk_EVP_PKEY_ASN1_METHOD_sort(app_methods);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PKEY_asn1_add_alias(int to, int from)
|
||||
{
|
||||
EVP_PKEY_ASN1_METHOD *ameth;
|
||||
ameth = EVP_PKEY_asn1_new(from, ASN1_PKEY_ALIAS, NULL, NULL);
|
||||
if (ameth == NULL)
|
||||
return 0;
|
||||
ameth->pkey_base_id = to;
|
||||
if (!EVP_PKEY_asn1_add0(ameth)) {
|
||||
EVP_PKEY_asn1_free(ameth);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EVP_PKEY_asn1_get0_info(int *ppkey_id, int *ppkey_base_id,
|
||||
int *ppkey_flags, const char **pinfo,
|
||||
const char **ppem_str,
|
||||
const EVP_PKEY_ASN1_METHOD *ameth)
|
||||
{
|
||||
if (!ameth)
|
||||
return 0;
|
||||
if (ppkey_id)
|
||||
*ppkey_id = ameth->pkey_id;
|
||||
if (ppkey_base_id)
|
||||
*ppkey_base_id = ameth->pkey_base_id;
|
||||
if (ppkey_flags)
|
||||
*ppkey_flags = ameth->pkey_flags;
|
||||
if (pinfo)
|
||||
*pinfo = ameth->info;
|
||||
if (ppem_str)
|
||||
*ppem_str = ameth->pem_str;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const EVP_PKEY_ASN1_METHOD *EVP_PKEY_get0_asn1(const EVP_PKEY *pkey)
|
||||
{
|
||||
return pkey->ameth;
|
||||
}
|
||||
|
||||
EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_new(int id, int flags,
|
||||
const char *pem_str, const char *info)
|
||||
{
|
||||
EVP_PKEY_ASN1_METHOD *ameth = OPENSSL_zalloc(sizeof(*ameth));
|
||||
|
||||
if (ameth == NULL)
|
||||
return NULL;
|
||||
|
||||
ameth->pkey_id = id;
|
||||
ameth->pkey_base_id = id;
|
||||
ameth->pkey_flags = flags | ASN1_PKEY_DYNAMIC;
|
||||
|
||||
if (info) {
|
||||
ameth->info = OPENSSL_strdup(info);
|
||||
if (ameth->info == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (pem_str) {
|
||||
ameth->pem_str = OPENSSL_strdup(pem_str);
|
||||
if (ameth->pem_str == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
return ameth;
|
||||
|
||||
err:
|
||||
EVP_PKEY_asn1_free(ameth);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_copy(EVP_PKEY_ASN1_METHOD *dst,
|
||||
const EVP_PKEY_ASN1_METHOD *src)
|
||||
{
|
||||
int pkey_id = dst->pkey_id;
|
||||
int pkey_base_id = dst->pkey_base_id;
|
||||
unsigned long pkey_flags = dst->pkey_flags;
|
||||
char *pem_str = dst->pem_str;
|
||||
char *info = dst->info;
|
||||
|
||||
*dst = *src;
|
||||
|
||||
/* We only copy the function pointers so restore the other values */
|
||||
dst->pkey_id = pkey_id;
|
||||
dst->pkey_base_id = pkey_base_id;
|
||||
dst->pkey_flags = pkey_flags;
|
||||
dst->pem_str = pem_str;
|
||||
dst->info = info;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_free(EVP_PKEY_ASN1_METHOD *ameth)
|
||||
{
|
||||
if (ameth && (ameth->pkey_flags & ASN1_PKEY_DYNAMIC)) {
|
||||
OPENSSL_free(ameth->pem_str);
|
||||
OPENSSL_free(ameth->info);
|
||||
OPENSSL_free(ameth);
|
||||
}
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_public(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*pub_decode) (EVP_PKEY *pk,
|
||||
const X509_PUBKEY *pub),
|
||||
int (*pub_encode) (X509_PUBKEY *pub,
|
||||
const EVP_PKEY *pk),
|
||||
int (*pub_cmp) (const EVP_PKEY *a,
|
||||
const EVP_PKEY *b),
|
||||
int (*pub_print) (BIO *out,
|
||||
const EVP_PKEY *pkey,
|
||||
int indent, ASN1_PCTX *pctx),
|
||||
int (*pkey_size) (const EVP_PKEY *pk),
|
||||
int (*pkey_bits) (const EVP_PKEY *pk))
|
||||
{
|
||||
ameth->pub_decode = pub_decode;
|
||||
ameth->pub_encode = pub_encode;
|
||||
ameth->pub_cmp = pub_cmp;
|
||||
ameth->pub_print = pub_print;
|
||||
ameth->pkey_size = pkey_size;
|
||||
ameth->pkey_bits = pkey_bits;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_private(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*priv_decode) (EVP_PKEY *pk,
|
||||
const PKCS8_PRIV_KEY_INFO
|
||||
*p8inf),
|
||||
int (*priv_encode) (PKCS8_PRIV_KEY_INFO *p8,
|
||||
const EVP_PKEY *pk),
|
||||
int (*priv_print) (BIO *out,
|
||||
const EVP_PKEY *pkey,
|
||||
int indent,
|
||||
ASN1_PCTX *pctx))
|
||||
{
|
||||
ameth->priv_decode = priv_decode;
|
||||
ameth->priv_encode = priv_encode;
|
||||
ameth->priv_print = priv_print;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_param(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*param_decode) (EVP_PKEY *pkey,
|
||||
const unsigned char **pder,
|
||||
int derlen),
|
||||
int (*param_encode) (const EVP_PKEY *pkey,
|
||||
unsigned char **pder),
|
||||
int (*param_missing) (const EVP_PKEY *pk),
|
||||
int (*param_copy) (EVP_PKEY *to,
|
||||
const EVP_PKEY *from),
|
||||
int (*param_cmp) (const EVP_PKEY *a,
|
||||
const EVP_PKEY *b),
|
||||
int (*param_print) (BIO *out,
|
||||
const EVP_PKEY *pkey,
|
||||
int indent, ASN1_PCTX *pctx))
|
||||
{
|
||||
ameth->param_decode = param_decode;
|
||||
ameth->param_encode = param_encode;
|
||||
ameth->param_missing = param_missing;
|
||||
ameth->param_copy = param_copy;
|
||||
ameth->param_cmp = param_cmp;
|
||||
ameth->param_print = param_print;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_free(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
void (*pkey_free) (EVP_PKEY *pkey))
|
||||
{
|
||||
ameth->pkey_free = pkey_free;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_ctrl(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*pkey_ctrl) (EVP_PKEY *pkey, int op,
|
||||
long arg1, void *arg2))
|
||||
{
|
||||
ameth->pkey_ctrl = pkey_ctrl;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*pkey_security_bits) (const EVP_PKEY
|
||||
*pk))
|
||||
{
|
||||
ameth->pkey_security_bits = pkey_security_bits;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_item(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*item_verify) (EVP_MD_CTX *ctx,
|
||||
const ASN1_ITEM *it,
|
||||
const void *data,
|
||||
const X509_ALGOR *a,
|
||||
const ASN1_BIT_STRING *sig,
|
||||
EVP_PKEY *pkey),
|
||||
int (*item_sign) (EVP_MD_CTX *ctx,
|
||||
const ASN1_ITEM *it,
|
||||
const void *data,
|
||||
X509_ALGOR *alg1,
|
||||
X509_ALGOR *alg2,
|
||||
ASN1_BIT_STRING *sig))
|
||||
{
|
||||
ameth->item_sign = item_sign;
|
||||
ameth->item_verify = item_verify;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_siginf(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*siginf_set) (X509_SIG_INFO *siginf,
|
||||
const X509_ALGOR *alg,
|
||||
const ASN1_STRING *sig))
|
||||
{
|
||||
ameth->siginf_set = siginf_set;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_check(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*pkey_check) (const EVP_PKEY *pk))
|
||||
{
|
||||
ameth->pkey_check = pkey_check;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_public_check(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*pkey_pub_check) (const EVP_PKEY *pk))
|
||||
{
|
||||
ameth->pkey_public_check = pkey_pub_check;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_param_check(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*pkey_param_check) (const EVP_PKEY *pk))
|
||||
{
|
||||
ameth->pkey_param_check = pkey_param_check;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_set_priv_key(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*set_priv_key) (EVP_PKEY *pk,
|
||||
const unsigned char
|
||||
*priv,
|
||||
size_t len))
|
||||
{
|
||||
ameth->set_priv_key = set_priv_key;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_set_pub_key(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*set_pub_key) (EVP_PKEY *pk,
|
||||
const unsigned char *pub,
|
||||
size_t len))
|
||||
{
|
||||
ameth->set_pub_key = set_pub_key;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_get_priv_key(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*get_priv_key) (const EVP_PKEY *pk,
|
||||
unsigned char *priv,
|
||||
size_t *len))
|
||||
{
|
||||
ameth->get_priv_key = get_priv_key;
|
||||
}
|
||||
|
||||
void EVP_PKEY_asn1_set_get_pub_key(EVP_PKEY_ASN1_METHOD *ameth,
|
||||
int (*get_pub_key) (const EVP_PKEY *pk,
|
||||
unsigned char *pub,
|
||||
size_t *len))
|
||||
{
|
||||
ameth->get_pub_key = get_pub_key;
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Generated by util/mkerr.pl DO NOT EDIT
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/asn1err.h>
|
||||
#include "crypto/asn1err.h"
|
||||
|
||||
#ifndef OPENSSL_NO_ERR
|
||||
|
||||
static const ERR_STRING_DATA ASN1_str_reasons[] = {
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ADDING_OBJECT), "adding object"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ASN1_PARSE_ERROR), "asn1 parse error"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ASN1_SIG_PARSE_ERROR),
|
||||
"asn1 sig parse error"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_AUX_ERROR), "aux error"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_OBJECT_HEADER), "bad object header"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BAD_TEMPLATE), "bad template"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BMPSTRING_IS_WRONG_LENGTH),
|
||||
"bmpstring is wrong length"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BN_LIB), "bn lib"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BOOLEAN_IS_WRONG_LENGTH),
|
||||
"boolean is wrong length"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_BUFFER_TOO_SMALL), "buffer too small"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER),
|
||||
"cipher has no object identifier"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_CONTEXT_NOT_INITIALISED),
|
||||
"context not initialised"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DATA_IS_WRONG), "data is wrong"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DECODE_ERROR), "decode error"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DEPTH_EXCEEDED), "depth exceeded"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED),
|
||||
"digest and key type not supported"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ENCODE_ERROR), "encode error"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_GETTING_TIME),
|
||||
"error getting time"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_LOADING_SECTION),
|
||||
"error loading section"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ERROR_SETTING_CIPHER_PARAMS),
|
||||
"error setting cipher params"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPECTING_AN_INTEGER),
|
||||
"expecting an integer"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPECTING_AN_OBJECT),
|
||||
"expecting an object"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPLICIT_LENGTH_MISMATCH),
|
||||
"explicit length mismatch"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED),
|
||||
"explicit tag not constructed"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_FIELD_MISSING), "field missing"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_FIRST_NUM_TOO_LARGE),
|
||||
"first num too large"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_GENERALIZEDTIME_IS_TOO_SHORT),
|
||||
"generalizedtime is too short"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_HEADER_TOO_LONG), "header too long"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_BITSTRING_FORMAT),
|
||||
"illegal bitstring format"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_BOOLEAN), "illegal boolean"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_CHARACTERS),
|
||||
"illegal characters"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_FORMAT), "illegal format"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_HEX), "illegal hex"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_IMPLICIT_TAG),
|
||||
"illegal implicit tag"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_INTEGER), "illegal integer"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_NEGATIVE_VALUE),
|
||||
"illegal negative value"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_NESTED_TAGGING),
|
||||
"illegal nested tagging"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_NULL), "illegal null"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_NULL_VALUE),
|
||||
"illegal null value"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_OBJECT), "illegal object"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_OPTIONAL_ANY),
|
||||
"illegal optional any"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE),
|
||||
"illegal options on item template"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_PADDING), "illegal padding"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_TAGGED_ANY),
|
||||
"illegal tagged any"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_TIME_VALUE),
|
||||
"illegal time value"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ILLEGAL_ZERO_CONTENT),
|
||||
"illegal zero content"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INTEGER_NOT_ASCII_FORMAT),
|
||||
"integer not ascii format"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG),
|
||||
"integer too large for long"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_BIT_STRING_BITS_LEFT),
|
||||
"invalid bit string bits left"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_BMPSTRING_LENGTH),
|
||||
"invalid bmpstring length"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_DIGIT), "invalid digit"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_MIME_TYPE), "invalid mime type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_MODIFIER), "invalid modifier"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_NUMBER), "invalid number"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_OBJECT_ENCODING),
|
||||
"invalid object encoding"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_SCRYPT_PARAMETERS),
|
||||
"invalid scrypt parameters"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_SEPARATOR), "invalid separator"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_STRING_TABLE_VALUE),
|
||||
"invalid string table value"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH),
|
||||
"invalid universalstring length"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_UTF8STRING),
|
||||
"invalid utf8string"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_INVALID_VALUE), "invalid value"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_LENGTH_TOO_LONG), "length too long"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_LIST_ERROR), "list error"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MIME_NO_CONTENT_TYPE),
|
||||
"mime no content type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MIME_PARSE_ERROR), "mime parse error"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MIME_SIG_PARSE_ERROR),
|
||||
"mime sig parse error"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MISSING_EOC), "missing eoc"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MISSING_SECOND_NUMBER),
|
||||
"missing second number"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MISSING_VALUE), "missing value"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MSTRING_NOT_UNIVERSAL),
|
||||
"mstring not universal"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_MSTRING_WRONG_TAG), "mstring wrong tag"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NESTED_ASN1_STRING),
|
||||
"nested asn1 string"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NESTED_TOO_DEEP), "nested too deep"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NON_HEX_CHARACTERS),
|
||||
"non hex characters"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NOT_ASCII_FORMAT), "not ascii format"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NOT_ENOUGH_DATA), "not enough data"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_CONTENT_TYPE), "no content type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_MATCHING_CHOICE_TYPE),
|
||||
"no matching choice type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_MULTIPART_BODY_FAILURE),
|
||||
"no multipart body failure"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_MULTIPART_BOUNDARY),
|
||||
"no multipart boundary"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NO_SIG_CONTENT_TYPE),
|
||||
"no sig content type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_NULL_IS_WRONG_LENGTH),
|
||||
"null is wrong length"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_OBJECT_NOT_ASCII_FORMAT),
|
||||
"object not ascii format"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_ODD_NUMBER_OF_CHARS),
|
||||
"odd number of chars"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SECOND_NUMBER_TOO_LARGE),
|
||||
"second number too large"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SEQUENCE_LENGTH_MISMATCH),
|
||||
"sequence length mismatch"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SEQUENCE_NOT_CONSTRUCTED),
|
||||
"sequence not constructed"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG),
|
||||
"sequence or set needs config"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SHORT_LINE), "short line"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_SIG_INVALID_MIME_TYPE),
|
||||
"sig invalid mime type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_STREAMING_NOT_SUPPORTED),
|
||||
"streaming not supported"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_STRING_TOO_LONG), "string too long"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_STRING_TOO_SHORT), "string too short"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD),
|
||||
"the asn1 object identifier is not known for this md"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TIME_NOT_ASCII_FORMAT),
|
||||
"time not ascii format"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TOO_LARGE), "too large"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TOO_LONG), "too long"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TOO_SMALL), "too small"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TYPE_NOT_CONSTRUCTED),
|
||||
"type not constructed"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_TYPE_NOT_PRIMITIVE),
|
||||
"type not primitive"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNEXPECTED_EOC), "unexpected eoc"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH),
|
||||
"universalstring is wrong length"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_DIGEST), "unknown digest"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_FORMAT), "unknown format"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM),
|
||||
"unknown message digest algorithm"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_OBJECT_TYPE),
|
||||
"unknown object type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE),
|
||||
"unknown public key type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM),
|
||||
"unknown signature algorithm"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNKNOWN_TAG), "unknown tag"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE),
|
||||
"unsupported any defined by type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_CIPHER),
|
||||
"unsupported cipher"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE),
|
||||
"unsupported public key type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UNSUPPORTED_TYPE), "unsupported type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_UTCTIME_IS_TOO_SHORT),
|
||||
"utctime is too short"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_INTEGER_TYPE),
|
||||
"wrong integer type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_PUBLIC_KEY_TYPE),
|
||||
"wrong public key type"},
|
||||
{ERR_PACK(ERR_LIB_ASN1, 0, ASN1_R_WRONG_TAG), "wrong tag"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int ossl_err_load_ASN1_strings(void)
|
||||
{
|
||||
#ifndef OPENSSL_NO_ERR
|
||||
if (ERR_reason_error_string(ASN1_str_reasons[0].error) == NULL)
|
||||
ERR_load_strings_const(ASN1_str_reasons);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,788 @@
|
||||
/*
|
||||
* Copyright 2002-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include "crypto/asn1.h"
|
||||
|
||||
#define ASN1_GEN_FLAG 0x10000
|
||||
#define ASN1_GEN_FLAG_IMP (ASN1_GEN_FLAG|1)
|
||||
#define ASN1_GEN_FLAG_EXP (ASN1_GEN_FLAG|2)
|
||||
#define ASN1_GEN_FLAG_TAG (ASN1_GEN_FLAG|3)
|
||||
#define ASN1_GEN_FLAG_BITWRAP (ASN1_GEN_FLAG|4)
|
||||
#define ASN1_GEN_FLAG_OCTWRAP (ASN1_GEN_FLAG|5)
|
||||
#define ASN1_GEN_FLAG_SEQWRAP (ASN1_GEN_FLAG|6)
|
||||
#define ASN1_GEN_FLAG_SETWRAP (ASN1_GEN_FLAG|7)
|
||||
#define ASN1_GEN_FLAG_FORMAT (ASN1_GEN_FLAG|8)
|
||||
|
||||
#define ASN1_GEN_STR(str,val) {str, sizeof(str) - 1, val}
|
||||
|
||||
#define ASN1_FLAG_EXP_MAX 20
|
||||
/* Maximum number of nested sequences */
|
||||
#define ASN1_GEN_SEQ_MAX_DEPTH 50
|
||||
|
||||
/* Input formats */
|
||||
|
||||
/* ASCII: default */
|
||||
#define ASN1_GEN_FORMAT_ASCII 1
|
||||
/* UTF8 */
|
||||
#define ASN1_GEN_FORMAT_UTF8 2
|
||||
/* Hex */
|
||||
#define ASN1_GEN_FORMAT_HEX 3
|
||||
/* List of bits */
|
||||
#define ASN1_GEN_FORMAT_BITLIST 4
|
||||
|
||||
struct tag_name_st {
|
||||
const char *strnam;
|
||||
int len;
|
||||
int tag;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int exp_tag;
|
||||
int exp_class;
|
||||
int exp_constructed;
|
||||
int exp_pad;
|
||||
long exp_len;
|
||||
} tag_exp_type;
|
||||
|
||||
typedef struct {
|
||||
int imp_tag;
|
||||
int imp_class;
|
||||
int utype;
|
||||
int format;
|
||||
const char *str;
|
||||
tag_exp_type exp_list[ASN1_FLAG_EXP_MAX];
|
||||
int exp_count;
|
||||
} tag_exp_arg;
|
||||
|
||||
static ASN1_TYPE *generate_v3(const char *str, X509V3_CTX *cnf, int depth,
|
||||
int *perr);
|
||||
static int bitstr_cb(const char *elem, int len, void *bitstr);
|
||||
static int asn1_cb(const char *elem, int len, void *bitstr);
|
||||
static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class,
|
||||
int exp_constructed, int exp_pad, int imp_ok);
|
||||
static int parse_tagging(const char *vstart, int vlen, int *ptag,
|
||||
int *pclass);
|
||||
static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf,
|
||||
int depth, int *perr);
|
||||
static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype);
|
||||
static int asn1_str2tag(const char *tagstr, int len);
|
||||
|
||||
ASN1_TYPE *ASN1_generate_nconf(const char *str, CONF *nconf)
|
||||
{
|
||||
X509V3_CTX cnf;
|
||||
|
||||
if (!nconf)
|
||||
return ASN1_generate_v3(str, NULL);
|
||||
|
||||
X509V3_set_nconf(&cnf, nconf);
|
||||
return ASN1_generate_v3(str, &cnf);
|
||||
}
|
||||
|
||||
ASN1_TYPE *ASN1_generate_v3(const char *str, X509V3_CTX *cnf)
|
||||
{
|
||||
int err = 0;
|
||||
ASN1_TYPE *ret = generate_v3(str, cnf, 0, &err);
|
||||
if (err)
|
||||
ERR_raise(ERR_LIB_ASN1, err);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ASN1_TYPE *generate_v3(const char *str, X509V3_CTX *cnf, int depth,
|
||||
int *perr)
|
||||
{
|
||||
ASN1_TYPE *ret;
|
||||
tag_exp_arg asn1_tags;
|
||||
tag_exp_type *etmp;
|
||||
|
||||
int i, len;
|
||||
|
||||
unsigned char *orig_der = NULL, *new_der = NULL;
|
||||
const unsigned char *cpy_start;
|
||||
unsigned char *p;
|
||||
const unsigned char *cp;
|
||||
int cpy_len;
|
||||
long hdr_len = 0;
|
||||
int hdr_constructed = 0, hdr_tag, hdr_class;
|
||||
int r;
|
||||
|
||||
asn1_tags.imp_tag = -1;
|
||||
asn1_tags.imp_class = -1;
|
||||
asn1_tags.format = ASN1_GEN_FORMAT_ASCII;
|
||||
asn1_tags.exp_count = 0;
|
||||
if (CONF_parse_list(str, ',', 1, asn1_cb, &asn1_tags) != 0) {
|
||||
*perr = ASN1_R_UNKNOWN_TAG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((asn1_tags.utype == V_ASN1_SEQUENCE)
|
||||
|| (asn1_tags.utype == V_ASN1_SET)) {
|
||||
if (!cnf) {
|
||||
*perr = ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG;
|
||||
return NULL;
|
||||
}
|
||||
if (depth >= ASN1_GEN_SEQ_MAX_DEPTH) {
|
||||
*perr = ASN1_R_ILLEGAL_NESTED_TAGGING;
|
||||
return NULL;
|
||||
}
|
||||
ret = asn1_multi(asn1_tags.utype, asn1_tags.str, cnf, depth, perr);
|
||||
} else
|
||||
ret = asn1_str2type(asn1_tags.str, asn1_tags.format, asn1_tags.utype);
|
||||
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
/* If no tagging return base type */
|
||||
if ((asn1_tags.imp_tag == -1) && (asn1_tags.exp_count == 0))
|
||||
return ret;
|
||||
|
||||
/* Generate the encoding */
|
||||
cpy_len = i2d_ASN1_TYPE(ret, &orig_der);
|
||||
ASN1_TYPE_free(ret);
|
||||
ret = NULL;
|
||||
/* Set point to start copying for modified encoding */
|
||||
cpy_start = orig_der;
|
||||
|
||||
/* Do we need IMPLICIT tagging? */
|
||||
if (asn1_tags.imp_tag != -1) {
|
||||
/* If IMPLICIT we will replace the underlying tag */
|
||||
/* Skip existing tag+len */
|
||||
r = ASN1_get_object(&cpy_start, &hdr_len, &hdr_tag, &hdr_class,
|
||||
cpy_len);
|
||||
if (r & 0x80)
|
||||
goto err;
|
||||
/* Update copy length */
|
||||
cpy_len -= cpy_start - orig_der;
|
||||
/*
|
||||
* For IMPLICIT tagging the length should match the original length
|
||||
* and constructed flag should be consistent.
|
||||
*/
|
||||
if (r & 0x1) {
|
||||
/* Indefinite length constructed */
|
||||
hdr_constructed = 2;
|
||||
hdr_len = 0;
|
||||
} else
|
||||
/* Just retain constructed flag */
|
||||
hdr_constructed = r & V_ASN1_CONSTRUCTED;
|
||||
/*
|
||||
* Work out new length with IMPLICIT tag: ignore constructed because
|
||||
* it will mess up if indefinite length
|
||||
*/
|
||||
len = ASN1_object_size(0, hdr_len, asn1_tags.imp_tag);
|
||||
} else
|
||||
len = cpy_len;
|
||||
|
||||
/* Work out length in any EXPLICIT, starting from end */
|
||||
|
||||
for (i = 0, etmp = asn1_tags.exp_list + asn1_tags.exp_count - 1;
|
||||
i < asn1_tags.exp_count; i++, etmp--) {
|
||||
/* Content length: number of content octets + any padding */
|
||||
len += etmp->exp_pad;
|
||||
etmp->exp_len = len;
|
||||
/* Total object length: length including new header */
|
||||
len = ASN1_object_size(0, len, etmp->exp_tag);
|
||||
}
|
||||
|
||||
/* Allocate buffer for new encoding */
|
||||
|
||||
new_der = OPENSSL_malloc(len);
|
||||
if (new_der == NULL)
|
||||
goto err;
|
||||
|
||||
/* Generate tagged encoding */
|
||||
|
||||
p = new_der;
|
||||
|
||||
/* Output explicit tags first */
|
||||
|
||||
for (i = 0, etmp = asn1_tags.exp_list; i < asn1_tags.exp_count;
|
||||
i++, etmp++) {
|
||||
ASN1_put_object(&p, etmp->exp_constructed, etmp->exp_len,
|
||||
etmp->exp_tag, etmp->exp_class);
|
||||
if (etmp->exp_pad)
|
||||
*p++ = 0;
|
||||
}
|
||||
|
||||
/* If IMPLICIT, output tag */
|
||||
|
||||
if (asn1_tags.imp_tag != -1) {
|
||||
if (asn1_tags.imp_class == V_ASN1_UNIVERSAL
|
||||
&& (asn1_tags.imp_tag == V_ASN1_SEQUENCE
|
||||
|| asn1_tags.imp_tag == V_ASN1_SET))
|
||||
hdr_constructed = V_ASN1_CONSTRUCTED;
|
||||
ASN1_put_object(&p, hdr_constructed, hdr_len,
|
||||
asn1_tags.imp_tag, asn1_tags.imp_class);
|
||||
}
|
||||
|
||||
/* Copy across original encoding */
|
||||
memcpy(p, cpy_start, cpy_len);
|
||||
|
||||
cp = new_der;
|
||||
|
||||
/* Obtain new ASN1_TYPE structure */
|
||||
ret = d2i_ASN1_TYPE(NULL, &cp, len);
|
||||
|
||||
err:
|
||||
OPENSSL_free(orig_der);
|
||||
OPENSSL_free(new_der);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static int asn1_cb(const char *elem, int len, void *bitstr)
|
||||
{
|
||||
tag_exp_arg *arg = bitstr;
|
||||
int i;
|
||||
int utype;
|
||||
int vlen = 0;
|
||||
const char *p, *vstart = NULL;
|
||||
|
||||
int tmp_tag, tmp_class;
|
||||
|
||||
if (elem == NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0, p = elem; i < len; p++, i++) {
|
||||
/* Look for the ':' in name value pairs */
|
||||
if (*p == ':') {
|
||||
vstart = p + 1;
|
||||
vlen = len - (vstart - elem);
|
||||
len = p - elem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
utype = asn1_str2tag(elem, len);
|
||||
|
||||
if (utype == -1) {
|
||||
ERR_raise_data(ERR_LIB_ASN1, ASN1_R_UNKNOWN_TAG, "tag=%s", elem);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If this is not a modifier mark end of string and exit */
|
||||
if (!(utype & ASN1_GEN_FLAG)) {
|
||||
arg->utype = utype;
|
||||
arg->str = vstart;
|
||||
/* If no value and not end of string, error */
|
||||
if (!vstart && elem[len]) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_MISSING_VALUE);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (utype) {
|
||||
|
||||
case ASN1_GEN_FLAG_IMP:
|
||||
/* Check for illegal multiple IMPLICIT tagging */
|
||||
if (arg->imp_tag != -1) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING);
|
||||
return -1;
|
||||
}
|
||||
if (!parse_tagging(vstart, vlen, &arg->imp_tag, &arg->imp_class))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case ASN1_GEN_FLAG_EXP:
|
||||
|
||||
if (!parse_tagging(vstart, vlen, &tmp_tag, &tmp_class))
|
||||
return -1;
|
||||
if (!append_exp(arg, tmp_tag, tmp_class, 1, 0, 0))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case ASN1_GEN_FLAG_SEQWRAP:
|
||||
if (!append_exp(arg, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, 1, 0, 1))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case ASN1_GEN_FLAG_SETWRAP:
|
||||
if (!append_exp(arg, V_ASN1_SET, V_ASN1_UNIVERSAL, 1, 0, 1))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case ASN1_GEN_FLAG_BITWRAP:
|
||||
if (!append_exp(arg, V_ASN1_BIT_STRING, V_ASN1_UNIVERSAL, 0, 1, 1))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case ASN1_GEN_FLAG_OCTWRAP:
|
||||
if (!append_exp(arg, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL, 0, 0, 1))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case ASN1_GEN_FLAG_FORMAT:
|
||||
if (!vstart) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT);
|
||||
return -1;
|
||||
}
|
||||
if (HAS_PREFIX(vstart, "ASCII"))
|
||||
arg->format = ASN1_GEN_FORMAT_ASCII;
|
||||
else if (HAS_PREFIX(vstart, "UTF8"))
|
||||
arg->format = ASN1_GEN_FORMAT_UTF8;
|
||||
else if (HAS_PREFIX(vstart, "HEX"))
|
||||
arg->format = ASN1_GEN_FORMAT_HEX;
|
||||
else if (HAS_PREFIX(vstart, "BITLIST"))
|
||||
arg->format = ASN1_GEN_FORMAT_BITLIST;
|
||||
else {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_FORMAT);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass)
|
||||
{
|
||||
long tag_num;
|
||||
char *eptr;
|
||||
if (!vstart)
|
||||
return 0;
|
||||
tag_num = strtoul(vstart, &eptr, 10);
|
||||
/* Check we haven't gone past max length: should be impossible */
|
||||
if (eptr && *eptr && (eptr > vstart + vlen))
|
||||
return 0;
|
||||
if (tag_num < 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_NUMBER);
|
||||
return 0;
|
||||
}
|
||||
*ptag = tag_num;
|
||||
/* If we have non numeric characters, parse them */
|
||||
if (eptr)
|
||||
vlen -= eptr - vstart;
|
||||
else
|
||||
vlen = 0;
|
||||
if (vlen) {
|
||||
switch (*eptr) {
|
||||
|
||||
case 'U':
|
||||
*pclass = V_ASN1_UNIVERSAL;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
*pclass = V_ASN1_APPLICATION;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
*pclass = V_ASN1_PRIVATE;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
*pclass = V_ASN1_CONTEXT_SPECIFIC;
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR_raise_data(ERR_LIB_ASN1, ASN1_R_INVALID_MODIFIER,
|
||||
"Char=%c", *eptr);
|
||||
return 0;
|
||||
|
||||
}
|
||||
} else
|
||||
*pclass = V_ASN1_CONTEXT_SPECIFIC;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
/* Handle multiple types: SET and SEQUENCE */
|
||||
|
||||
static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf,
|
||||
int depth, int *perr)
|
||||
{
|
||||
ASN1_TYPE *ret = NULL;
|
||||
STACK_OF(ASN1_TYPE) *sk = NULL;
|
||||
STACK_OF(CONF_VALUE) *sect = NULL;
|
||||
unsigned char *der = NULL;
|
||||
int derlen;
|
||||
int i;
|
||||
sk = sk_ASN1_TYPE_new_null();
|
||||
if (!sk)
|
||||
goto bad;
|
||||
if (section) {
|
||||
if (!cnf)
|
||||
goto bad;
|
||||
sect = X509V3_get_section(cnf, (char *)section);
|
||||
if (!sect)
|
||||
goto bad;
|
||||
for (i = 0; i < sk_CONF_VALUE_num(sect); i++) {
|
||||
ASN1_TYPE *typ =
|
||||
generate_v3(sk_CONF_VALUE_value(sect, i)->value, cnf,
|
||||
depth + 1, perr);
|
||||
if (!typ)
|
||||
goto bad;
|
||||
if (!sk_ASN1_TYPE_push(sk, typ))
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we has a STACK of the components, convert to the correct form
|
||||
*/
|
||||
|
||||
if (utype == V_ASN1_SET)
|
||||
derlen = i2d_ASN1_SET_ANY(sk, &der);
|
||||
else
|
||||
derlen = i2d_ASN1_SEQUENCE_ANY(sk, &der);
|
||||
|
||||
if (derlen < 0)
|
||||
goto bad;
|
||||
if ((ret = ASN1_TYPE_new()) == NULL)
|
||||
goto bad;
|
||||
if ((ret->value.asn1_string = ASN1_STRING_type_new(utype)) == NULL)
|
||||
goto bad;
|
||||
|
||||
ret->type = utype;
|
||||
ret->value.asn1_string->data = der;
|
||||
ret->value.asn1_string->length = derlen;
|
||||
|
||||
der = NULL;
|
||||
|
||||
bad:
|
||||
|
||||
OPENSSL_free(der);
|
||||
|
||||
sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free);
|
||||
X509V3_section_free(cnf, sect);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class,
|
||||
int exp_constructed, int exp_pad, int imp_ok)
|
||||
{
|
||||
tag_exp_type *exp_tmp;
|
||||
/* Can only have IMPLICIT if permitted */
|
||||
if ((arg->imp_tag != -1) && !imp_ok) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_IMPLICIT_TAG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg->exp_count == ASN1_FLAG_EXP_MAX) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_DEPTH_EXCEEDED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
exp_tmp = &arg->exp_list[arg->exp_count++];
|
||||
|
||||
/*
|
||||
* If IMPLICIT set tag to implicit value then reset implicit tag since it
|
||||
* has been used.
|
||||
*/
|
||||
if (arg->imp_tag != -1) {
|
||||
exp_tmp->exp_tag = arg->imp_tag;
|
||||
exp_tmp->exp_class = arg->imp_class;
|
||||
arg->imp_tag = -1;
|
||||
arg->imp_class = -1;
|
||||
} else {
|
||||
exp_tmp->exp_tag = exp_tag;
|
||||
exp_tmp->exp_class = exp_class;
|
||||
}
|
||||
exp_tmp->exp_constructed = exp_constructed;
|
||||
exp_tmp->exp_pad = exp_pad;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_str2tag(const char *tagstr, int len)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct tag_name_st *tntmp;
|
||||
static const struct tag_name_st tnst[] = {
|
||||
ASN1_GEN_STR("BOOL", V_ASN1_BOOLEAN),
|
||||
ASN1_GEN_STR("BOOLEAN", V_ASN1_BOOLEAN),
|
||||
ASN1_GEN_STR("NULL", V_ASN1_NULL),
|
||||
ASN1_GEN_STR("INT", V_ASN1_INTEGER),
|
||||
ASN1_GEN_STR("INTEGER", V_ASN1_INTEGER),
|
||||
ASN1_GEN_STR("ENUM", V_ASN1_ENUMERATED),
|
||||
ASN1_GEN_STR("ENUMERATED", V_ASN1_ENUMERATED),
|
||||
ASN1_GEN_STR("OID", V_ASN1_OBJECT),
|
||||
ASN1_GEN_STR("OBJECT", V_ASN1_OBJECT),
|
||||
ASN1_GEN_STR("UTCTIME", V_ASN1_UTCTIME),
|
||||
ASN1_GEN_STR("UTC", V_ASN1_UTCTIME),
|
||||
ASN1_GEN_STR("GENERALIZEDTIME", V_ASN1_GENERALIZEDTIME),
|
||||
ASN1_GEN_STR("GENTIME", V_ASN1_GENERALIZEDTIME),
|
||||
ASN1_GEN_STR("OCT", V_ASN1_OCTET_STRING),
|
||||
ASN1_GEN_STR("OCTETSTRING", V_ASN1_OCTET_STRING),
|
||||
ASN1_GEN_STR("BITSTR", V_ASN1_BIT_STRING),
|
||||
ASN1_GEN_STR("BITSTRING", V_ASN1_BIT_STRING),
|
||||
ASN1_GEN_STR("UNIVERSALSTRING", V_ASN1_UNIVERSALSTRING),
|
||||
ASN1_GEN_STR("UNIV", V_ASN1_UNIVERSALSTRING),
|
||||
ASN1_GEN_STR("IA5", V_ASN1_IA5STRING),
|
||||
ASN1_GEN_STR("IA5STRING", V_ASN1_IA5STRING),
|
||||
ASN1_GEN_STR("UTF8", V_ASN1_UTF8STRING),
|
||||
ASN1_GEN_STR("UTF8String", V_ASN1_UTF8STRING),
|
||||
ASN1_GEN_STR("BMP", V_ASN1_BMPSTRING),
|
||||
ASN1_GEN_STR("BMPSTRING", V_ASN1_BMPSTRING),
|
||||
ASN1_GEN_STR("VISIBLESTRING", V_ASN1_VISIBLESTRING),
|
||||
ASN1_GEN_STR("VISIBLE", V_ASN1_VISIBLESTRING),
|
||||
ASN1_GEN_STR("PRINTABLESTRING", V_ASN1_PRINTABLESTRING),
|
||||
ASN1_GEN_STR("PRINTABLE", V_ASN1_PRINTABLESTRING),
|
||||
ASN1_GEN_STR("T61", V_ASN1_T61STRING),
|
||||
ASN1_GEN_STR("T61STRING", V_ASN1_T61STRING),
|
||||
ASN1_GEN_STR("TELETEXSTRING", V_ASN1_T61STRING),
|
||||
ASN1_GEN_STR("GeneralString", V_ASN1_GENERALSTRING),
|
||||
ASN1_GEN_STR("GENSTR", V_ASN1_GENERALSTRING),
|
||||
ASN1_GEN_STR("NUMERIC", V_ASN1_NUMERICSTRING),
|
||||
ASN1_GEN_STR("NUMERICSTRING", V_ASN1_NUMERICSTRING),
|
||||
|
||||
/* Special cases */
|
||||
ASN1_GEN_STR("SEQUENCE", V_ASN1_SEQUENCE),
|
||||
ASN1_GEN_STR("SEQ", V_ASN1_SEQUENCE),
|
||||
ASN1_GEN_STR("SET", V_ASN1_SET),
|
||||
/* type modifiers */
|
||||
/* Explicit tag */
|
||||
ASN1_GEN_STR("EXP", ASN1_GEN_FLAG_EXP),
|
||||
ASN1_GEN_STR("EXPLICIT", ASN1_GEN_FLAG_EXP),
|
||||
/* Implicit tag */
|
||||
ASN1_GEN_STR("IMP", ASN1_GEN_FLAG_IMP),
|
||||
ASN1_GEN_STR("IMPLICIT", ASN1_GEN_FLAG_IMP),
|
||||
/* OCTET STRING wrapper */
|
||||
ASN1_GEN_STR("OCTWRAP", ASN1_GEN_FLAG_OCTWRAP),
|
||||
/* SEQUENCE wrapper */
|
||||
ASN1_GEN_STR("SEQWRAP", ASN1_GEN_FLAG_SEQWRAP),
|
||||
/* SET wrapper */
|
||||
ASN1_GEN_STR("SETWRAP", ASN1_GEN_FLAG_SETWRAP),
|
||||
/* BIT STRING wrapper */
|
||||
ASN1_GEN_STR("BITWRAP", ASN1_GEN_FLAG_BITWRAP),
|
||||
ASN1_GEN_STR("FORM", ASN1_GEN_FLAG_FORMAT),
|
||||
ASN1_GEN_STR("FORMAT", ASN1_GEN_FLAG_FORMAT),
|
||||
};
|
||||
|
||||
if (len == -1)
|
||||
len = strlen(tagstr);
|
||||
|
||||
tntmp = tnst;
|
||||
for (i = 0; i < OSSL_NELEM(tnst); i++, tntmp++) {
|
||||
if ((len == tntmp->len)
|
||||
&& (OPENSSL_strncasecmp(tntmp->strnam, tagstr, len) == 0))
|
||||
return tntmp->tag;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype)
|
||||
{
|
||||
ASN1_TYPE *atmp = NULL;
|
||||
CONF_VALUE vtmp;
|
||||
unsigned char *rdata;
|
||||
long rdlen;
|
||||
int no_unused = 1;
|
||||
|
||||
if ((atmp = ASN1_TYPE_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!str)
|
||||
str = "";
|
||||
|
||||
switch (utype) {
|
||||
|
||||
case V_ASN1_NULL:
|
||||
if (str && *str) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_NULL_VALUE);
|
||||
goto bad_form;
|
||||
}
|
||||
break;
|
||||
|
||||
case V_ASN1_BOOLEAN:
|
||||
if (format != ASN1_GEN_FORMAT_ASCII) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_NOT_ASCII_FORMAT);
|
||||
goto bad_form;
|
||||
}
|
||||
vtmp.name = NULL;
|
||||
vtmp.section = NULL;
|
||||
vtmp.value = (char *)str;
|
||||
if (!X509V3_get_value_bool(&vtmp, &atmp->value.boolean)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_BOOLEAN);
|
||||
goto bad_str;
|
||||
}
|
||||
break;
|
||||
|
||||
case V_ASN1_INTEGER:
|
||||
case V_ASN1_ENUMERATED:
|
||||
if (format != ASN1_GEN_FORMAT_ASCII) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INTEGER_NOT_ASCII_FORMAT);
|
||||
goto bad_form;
|
||||
}
|
||||
if ((atmp->value.integer
|
||||
= s2i_ASN1_INTEGER(NULL, str)) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_INTEGER);
|
||||
goto bad_str;
|
||||
}
|
||||
break;
|
||||
|
||||
case V_ASN1_OBJECT:
|
||||
if (format != ASN1_GEN_FORMAT_ASCII) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_OBJECT_NOT_ASCII_FORMAT);
|
||||
goto bad_form;
|
||||
}
|
||||
if ((atmp->value.object = OBJ_txt2obj(str, 0)) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_OBJECT);
|
||||
goto bad_str;
|
||||
}
|
||||
break;
|
||||
|
||||
case V_ASN1_UTCTIME:
|
||||
case V_ASN1_GENERALIZEDTIME:
|
||||
if (format != ASN1_GEN_FORMAT_ASCII) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TIME_NOT_ASCII_FORMAT);
|
||||
goto bad_form;
|
||||
}
|
||||
if ((atmp->value.asn1_string = ASN1_STRING_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto bad_str;
|
||||
}
|
||||
if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto bad_str;
|
||||
}
|
||||
atmp->value.asn1_string->type = utype;
|
||||
if (!ASN1_TIME_check(atmp->value.asn1_string)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_TIME_VALUE);
|
||||
goto bad_str;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case V_ASN1_BMPSTRING:
|
||||
case V_ASN1_PRINTABLESTRING:
|
||||
case V_ASN1_IA5STRING:
|
||||
case V_ASN1_T61STRING:
|
||||
case V_ASN1_UTF8STRING:
|
||||
case V_ASN1_VISIBLESTRING:
|
||||
case V_ASN1_UNIVERSALSTRING:
|
||||
case V_ASN1_GENERALSTRING:
|
||||
case V_ASN1_NUMERICSTRING:
|
||||
if (format == ASN1_GEN_FORMAT_ASCII)
|
||||
format = MBSTRING_ASC;
|
||||
else if (format == ASN1_GEN_FORMAT_UTF8)
|
||||
format = MBSTRING_UTF8;
|
||||
else {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_FORMAT);
|
||||
goto bad_form;
|
||||
}
|
||||
|
||||
if (ASN1_mbstring_copy(&atmp->value.asn1_string, (unsigned char *)str,
|
||||
-1, format, ASN1_tag2bit(utype)) <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto bad_str;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case V_ASN1_BIT_STRING:
|
||||
case V_ASN1_OCTET_STRING:
|
||||
if ((atmp->value.asn1_string = ASN1_STRING_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto bad_form;
|
||||
}
|
||||
|
||||
if (format == ASN1_GEN_FORMAT_HEX) {
|
||||
if ((rdata = OPENSSL_hexstr2buf(str, &rdlen)) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_HEX);
|
||||
goto bad_str;
|
||||
}
|
||||
atmp->value.asn1_string->data = rdata;
|
||||
atmp->value.asn1_string->length = rdlen;
|
||||
atmp->value.asn1_string->type = utype;
|
||||
} else if (format == ASN1_GEN_FORMAT_ASCII) {
|
||||
if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto bad_str;
|
||||
}
|
||||
} else if ((format == ASN1_GEN_FORMAT_BITLIST)
|
||||
&& (utype == V_ASN1_BIT_STRING)) {
|
||||
if (!CONF_parse_list
|
||||
(str, ',', 1, bitstr_cb, atmp->value.bit_string)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_LIST_ERROR);
|
||||
goto bad_str;
|
||||
}
|
||||
no_unused = 0;
|
||||
|
||||
} else {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT);
|
||||
goto bad_form;
|
||||
}
|
||||
|
||||
if ((utype == V_ASN1_BIT_STRING) && no_unused)
|
||||
ossl_asn1_string_set_bits_left(atmp->value.asn1_string, 0);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_TYPE);
|
||||
goto bad_str;
|
||||
}
|
||||
|
||||
atmp->type = utype;
|
||||
return atmp;
|
||||
|
||||
bad_str:
|
||||
ERR_add_error_data(2, "string=", str);
|
||||
bad_form:
|
||||
|
||||
ASN1_TYPE_free(atmp);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
static int bitstr_cb(const char *elem, int len, void *bitstr)
|
||||
{
|
||||
long bitnum;
|
||||
char *eptr;
|
||||
if (!elem)
|
||||
return 0;
|
||||
bitnum = strtoul(elem, &eptr, 10);
|
||||
if (eptr && *eptr && (eptr != elem + len))
|
||||
return 0;
|
||||
if (bitnum < 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_NUMBER);
|
||||
return 0;
|
||||
}
|
||||
if (!ASN1_BIT_STRING_set_bit(bitstr, bitnum, 1)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mask_cb(const char *elem, int len, void *arg)
|
||||
{
|
||||
unsigned long *pmask = arg, tmpmask;
|
||||
int tag;
|
||||
if (elem == NULL)
|
||||
return 0;
|
||||
if (len == 3 && HAS_PREFIX(elem, "DIR")) {
|
||||
*pmask |= B_ASN1_DIRECTORYSTRING;
|
||||
return 1;
|
||||
}
|
||||
tag = asn1_str2tag(elem, len);
|
||||
if (!tag || (tag & ASN1_GEN_FLAG))
|
||||
return 0;
|
||||
tmpmask = ASN1_tag2bit(tag);
|
||||
if (!tmpmask)
|
||||
return 0;
|
||||
*pmask |= tmpmask;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ASN1_str2mask(const char *str, unsigned long *pmask)
|
||||
{
|
||||
*pmask = 0;
|
||||
return CONF_parse_list(str, '|', 1, mask_cb, pmask);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* We need to use the low level ASN1 items until they are removed */
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/cms.h>
|
||||
#include <openssl/dh.h>
|
||||
#include <openssl/ocsp.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/x509_acert.h>
|
||||
|
||||
#include "asn1_item_list.h"
|
||||
|
||||
const ASN1_ITEM *ASN1_ITEM_lookup(const char *name)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < OSSL_NELEM(asn1_item_list); i++) {
|
||||
const ASN1_ITEM *it = ASN1_ITEM_ptr(asn1_item_list[i]);
|
||||
|
||||
if (strcmp(it->sname, name) == 0)
|
||||
return it;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const ASN1_ITEM *ASN1_ITEM_get(size_t i)
|
||||
{
|
||||
if (i >= OSSL_NELEM(asn1_item_list))
|
||||
return NULL;
|
||||
return ASN1_ITEM_ptr(asn1_item_list[i]);
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2000-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
static ASN1_ITEM_EXP *asn1_item_list[] = {
|
||||
|
||||
ASN1_ITEM_ref(ACCESS_DESCRIPTION),
|
||||
#ifndef OPENSSL_NO_RFC3779
|
||||
ASN1_ITEM_ref(ASIdOrRange),
|
||||
ASN1_ITEM_ref(ASIdentifierChoice),
|
||||
ASN1_ITEM_ref(ASIdentifiers),
|
||||
#endif
|
||||
ASN1_ITEM_ref(ASN1_ANY),
|
||||
ASN1_ITEM_ref(ASN1_BIT_STRING),
|
||||
ASN1_ITEM_ref(ASN1_BMPSTRING),
|
||||
ASN1_ITEM_ref(ASN1_BOOLEAN),
|
||||
ASN1_ITEM_ref(ASN1_ENUMERATED),
|
||||
ASN1_ITEM_ref(ASN1_FBOOLEAN),
|
||||
ASN1_ITEM_ref(ASN1_GENERALIZEDTIME),
|
||||
ASN1_ITEM_ref(ASN1_GENERALSTRING),
|
||||
ASN1_ITEM_ref(ASN1_IA5STRING),
|
||||
ASN1_ITEM_ref(ASN1_INTEGER),
|
||||
ASN1_ITEM_ref(ASN1_NULL),
|
||||
ASN1_ITEM_ref(ASN1_OBJECT),
|
||||
ASN1_ITEM_ref(ASN1_OCTET_STRING_NDEF),
|
||||
ASN1_ITEM_ref(ASN1_OCTET_STRING),
|
||||
ASN1_ITEM_ref(ASN1_PRINTABLESTRING),
|
||||
ASN1_ITEM_ref(ASN1_PRINTABLE),
|
||||
ASN1_ITEM_ref(ASN1_SEQUENCE_ANY),
|
||||
ASN1_ITEM_ref(ASN1_SEQUENCE),
|
||||
ASN1_ITEM_ref(ASN1_SET_ANY),
|
||||
ASN1_ITEM_ref(ASN1_T61STRING),
|
||||
ASN1_ITEM_ref(ASN1_TBOOLEAN),
|
||||
ASN1_ITEM_ref(ASN1_TIME),
|
||||
ASN1_ITEM_ref(ASN1_UNIVERSALSTRING),
|
||||
ASN1_ITEM_ref(ASN1_UTCTIME),
|
||||
ASN1_ITEM_ref(ASN1_UTF8STRING),
|
||||
ASN1_ITEM_ref(ASN1_VISIBLESTRING),
|
||||
#ifndef OPENSSL_NO_RFC3779
|
||||
ASN1_ITEM_ref(ASRange),
|
||||
#endif
|
||||
ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS),
|
||||
ASN1_ITEM_ref(AUTHORITY_KEYID),
|
||||
ASN1_ITEM_ref(BASIC_CONSTRAINTS),
|
||||
ASN1_ITEM_ref(BIGNUM),
|
||||
ASN1_ITEM_ref(CBIGNUM),
|
||||
ASN1_ITEM_ref(CERTIFICATEPOLICIES),
|
||||
#ifndef OPENSSL_NO_CMS
|
||||
ASN1_ITEM_ref(CMS_ContentInfo),
|
||||
ASN1_ITEM_ref(CMS_EnvelopedData),
|
||||
ASN1_ITEM_ref(CMS_ReceiptRequest),
|
||||
#endif
|
||||
ASN1_ITEM_ref(CRL_DIST_POINTS),
|
||||
#ifndef OPENSSL_NO_DH
|
||||
ASN1_ITEM_ref(DHparams),
|
||||
#endif
|
||||
ASN1_ITEM_ref(DIRECTORYSTRING),
|
||||
ASN1_ITEM_ref(DISPLAYTEXT),
|
||||
ASN1_ITEM_ref(DIST_POINT_NAME),
|
||||
ASN1_ITEM_ref(DIST_POINT),
|
||||
#ifndef OPENSSL_NO_EC
|
||||
# ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
ASN1_ITEM_ref(ECPARAMETERS),
|
||||
ASN1_ITEM_ref(ECPKPARAMETERS),
|
||||
# endif
|
||||
#endif
|
||||
ASN1_ITEM_ref(EDIPARTYNAME),
|
||||
ASN1_ITEM_ref(EXTENDED_KEY_USAGE),
|
||||
ASN1_ITEM_ref(GENERAL_NAMES),
|
||||
ASN1_ITEM_ref(GENERAL_NAME),
|
||||
ASN1_ITEM_ref(GENERAL_SUBTREE),
|
||||
#ifndef OPENSSL_NO_RFC3779
|
||||
ASN1_ITEM_ref(IPAddressChoice),
|
||||
ASN1_ITEM_ref(IPAddressFamily),
|
||||
ASN1_ITEM_ref(IPAddressOrRange),
|
||||
ASN1_ITEM_ref(IPAddressRange),
|
||||
#endif
|
||||
ASN1_ITEM_ref(ISSUING_DIST_POINT),
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
ASN1_ITEM_ref(LONG),
|
||||
#endif
|
||||
ASN1_ITEM_ref(NAME_CONSTRAINTS),
|
||||
ASN1_ITEM_ref(NETSCAPE_CERT_SEQUENCE),
|
||||
ASN1_ITEM_ref(NETSCAPE_SPKAC),
|
||||
ASN1_ITEM_ref(NETSCAPE_SPKI),
|
||||
ASN1_ITEM_ref(NOTICEREF),
|
||||
#ifndef OPENSSL_NO_OCSP
|
||||
ASN1_ITEM_ref(OCSP_BASICRESP),
|
||||
ASN1_ITEM_ref(OCSP_CERTID),
|
||||
ASN1_ITEM_ref(OCSP_CERTSTATUS),
|
||||
ASN1_ITEM_ref(OCSP_CRLID),
|
||||
ASN1_ITEM_ref(OCSP_ONEREQ),
|
||||
ASN1_ITEM_ref(OCSP_REQINFO),
|
||||
ASN1_ITEM_ref(OCSP_REQUEST),
|
||||
ASN1_ITEM_ref(OCSP_RESPBYTES),
|
||||
ASN1_ITEM_ref(OCSP_RESPDATA),
|
||||
ASN1_ITEM_ref(OCSP_RESPID),
|
||||
ASN1_ITEM_ref(OCSP_RESPONSE),
|
||||
ASN1_ITEM_ref(OCSP_REVOKEDINFO),
|
||||
ASN1_ITEM_ref(OCSP_SERVICELOC),
|
||||
ASN1_ITEM_ref(OCSP_SIGNATURE),
|
||||
ASN1_ITEM_ref(OCSP_SINGLERESP),
|
||||
#endif
|
||||
ASN1_ITEM_ref(OTHERNAME),
|
||||
ASN1_ITEM_ref(PBE2PARAM),
|
||||
ASN1_ITEM_ref(PBEPARAM),
|
||||
ASN1_ITEM_ref(PBKDF2PARAM),
|
||||
ASN1_ITEM_ref(PKCS12_AUTHSAFES),
|
||||
ASN1_ITEM_ref(PKCS12_BAGS),
|
||||
ASN1_ITEM_ref(PKCS12_MAC_DATA),
|
||||
ASN1_ITEM_ref(PKCS12_SAFEBAGS),
|
||||
ASN1_ITEM_ref(PKCS12_SAFEBAG),
|
||||
ASN1_ITEM_ref(PKCS12),
|
||||
ASN1_ITEM_ref(PKCS7_ATTR_SIGN),
|
||||
ASN1_ITEM_ref(PKCS7_ATTR_VERIFY),
|
||||
ASN1_ITEM_ref(PKCS7_DIGEST),
|
||||
ASN1_ITEM_ref(PKCS7_ENCRYPT),
|
||||
ASN1_ITEM_ref(PKCS7_ENC_CONTENT),
|
||||
ASN1_ITEM_ref(PKCS7_ENVELOPE),
|
||||
ASN1_ITEM_ref(PKCS7_ISSUER_AND_SERIAL),
|
||||
ASN1_ITEM_ref(PKCS7_RECIP_INFO),
|
||||
ASN1_ITEM_ref(PKCS7_SIGNED),
|
||||
ASN1_ITEM_ref(PKCS7_SIGNER_INFO),
|
||||
ASN1_ITEM_ref(PKCS7_SIGN_ENVELOPE),
|
||||
ASN1_ITEM_ref(PKCS7),
|
||||
ASN1_ITEM_ref(PKCS8_PRIV_KEY_INFO),
|
||||
ASN1_ITEM_ref(PKEY_USAGE_PERIOD),
|
||||
ASN1_ITEM_ref(POLICYINFO),
|
||||
ASN1_ITEM_ref(POLICYQUALINFO),
|
||||
ASN1_ITEM_ref(POLICY_CONSTRAINTS),
|
||||
ASN1_ITEM_ref(POLICY_MAPPINGS),
|
||||
ASN1_ITEM_ref(POLICY_MAPPING),
|
||||
ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION),
|
||||
ASN1_ITEM_ref(PROXY_POLICY),
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
ASN1_ITEM_ref(RSAPrivateKey),
|
||||
ASN1_ITEM_ref(RSAPublicKey),
|
||||
ASN1_ITEM_ref(RSA_OAEP_PARAMS),
|
||||
ASN1_ITEM_ref(RSA_PSS_PARAMS),
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_SCRYPT
|
||||
ASN1_ITEM_ref(SCRYPT_PARAMS),
|
||||
#endif
|
||||
ASN1_ITEM_ref(SXNETID),
|
||||
ASN1_ITEM_ref(SXNET),
|
||||
ASN1_ITEM_ref(ISSUER_SIGN_TOOL),
|
||||
ASN1_ITEM_ref(USERNOTICE),
|
||||
ASN1_ITEM_ref(X509_ACERT),
|
||||
ASN1_ITEM_ref(X509_ALGORS),
|
||||
ASN1_ITEM_ref(X509_ALGOR),
|
||||
ASN1_ITEM_ref(X509_ATTRIBUTE),
|
||||
ASN1_ITEM_ref(X509_CERT_AUX),
|
||||
ASN1_ITEM_ref(X509_CINF),
|
||||
ASN1_ITEM_ref(X509_CRL_INFO),
|
||||
ASN1_ITEM_ref(X509_CRL),
|
||||
ASN1_ITEM_ref(X509_EXTENSIONS),
|
||||
ASN1_ITEM_ref(X509_EXTENSION),
|
||||
ASN1_ITEM_ref(X509_NAME_ENTRY),
|
||||
ASN1_ITEM_ref(X509_NAME),
|
||||
ASN1_ITEM_ref(X509_PUBKEY),
|
||||
ASN1_ITEM_ref(X509_REQ_INFO),
|
||||
ASN1_ITEM_ref(X509_REQ),
|
||||
ASN1_ITEM_ref(X509_REVOKED),
|
||||
ASN1_ITEM_ref(X509_SIG),
|
||||
ASN1_ITEM_ref(X509_VAL),
|
||||
ASN1_ITEM_ref(X509),
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
ASN1_ITEM_ref(ZLONG),
|
||||
#endif
|
||||
ASN1_ITEM_ref(INT32),
|
||||
ASN1_ITEM_ref(UINT32),
|
||||
ASN1_ITEM_ref(ZINT32),
|
||||
ASN1_ITEM_ref(ZUINT32),
|
||||
ASN1_ITEM_ref(INT64),
|
||||
ASN1_ITEM_ref(UINT64),
|
||||
ASN1_ITEM_ref(ZINT64),
|
||||
ASN1_ITEM_ref(ZUINT64),
|
||||
};
|
||||
@@ -0,0 +1,473 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
#include "asn1_local.h"
|
||||
|
||||
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
|
||||
long max);
|
||||
static void asn1_put_length(unsigned char **pp, int length);
|
||||
|
||||
static int _asn1_check_infinite_end(const unsigned char **p, long len)
|
||||
{
|
||||
/*
|
||||
* If there is 0 or 1 byte left, the length check should pick things up
|
||||
*/
|
||||
if (len <= 0) {
|
||||
return 1;
|
||||
} else {
|
||||
if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) {
|
||||
(*p) += 2;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ASN1_check_infinite_end(unsigned char **p, long len)
|
||||
{
|
||||
return _asn1_check_infinite_end((const unsigned char **)p, len);
|
||||
}
|
||||
|
||||
int ASN1_const_check_infinite_end(const unsigned char **p, long len)
|
||||
{
|
||||
return _asn1_check_infinite_end(p, len);
|
||||
}
|
||||
|
||||
int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
|
||||
int *pclass, long omax)
|
||||
{
|
||||
int i, ret;
|
||||
long len;
|
||||
const unsigned char *p = *pp;
|
||||
int tag, xclass, inf;
|
||||
long max = omax;
|
||||
|
||||
if (omax <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_SMALL);
|
||||
return 0x80;
|
||||
}
|
||||
ret = (*p & V_ASN1_CONSTRUCTED);
|
||||
xclass = (*p & V_ASN1_PRIVATE);
|
||||
i = *p & V_ASN1_PRIMITIVE_TAG;
|
||||
if (i == V_ASN1_PRIMITIVE_TAG) { /* high-tag */
|
||||
p++;
|
||||
if (--max == 0)
|
||||
goto err;
|
||||
len = 0;
|
||||
while (*p & 0x80) {
|
||||
len <<= 7L;
|
||||
len |= *(p++) & 0x7f;
|
||||
if (--max == 0)
|
||||
goto err;
|
||||
if (len > (INT_MAX >> 7L))
|
||||
goto err;
|
||||
}
|
||||
len <<= 7L;
|
||||
len |= *(p++) & 0x7f;
|
||||
tag = (int)len;
|
||||
if (--max == 0)
|
||||
goto err;
|
||||
} else {
|
||||
tag = i;
|
||||
p++;
|
||||
if (--max == 0)
|
||||
goto err;
|
||||
}
|
||||
*ptag = tag;
|
||||
*pclass = xclass;
|
||||
if (!asn1_get_length(&p, &inf, plength, max))
|
||||
goto err;
|
||||
|
||||
if (inf && !(ret & V_ASN1_CONSTRUCTED))
|
||||
goto err;
|
||||
|
||||
if (*plength > (omax - (p - *pp))) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LONG);
|
||||
/*
|
||||
* Set this so that even if things are not long enough the values are
|
||||
* set correctly
|
||||
*/
|
||||
ret |= 0x80;
|
||||
}
|
||||
*pp = p;
|
||||
return ret | inf;
|
||||
err:
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_HEADER_TOO_LONG);
|
||||
return 0x80;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode a length field.
|
||||
* The short form is a single byte defining a length 0 - 127.
|
||||
* The long form is a byte 0 - 127 with the top bit set and this indicates
|
||||
* the number of following octets that contain the length. These octets
|
||||
* are stored most significant digit first.
|
||||
*/
|
||||
static int asn1_get_length(const unsigned char **pp, int *inf, long *rl,
|
||||
long max)
|
||||
{
|
||||
const unsigned char *p = *pp;
|
||||
unsigned long ret = 0;
|
||||
int i;
|
||||
|
||||
if (max-- < 1)
|
||||
return 0;
|
||||
if (*p == 0x80) {
|
||||
*inf = 1;
|
||||
p++;
|
||||
} else {
|
||||
*inf = 0;
|
||||
i = *p & 0x7f;
|
||||
if (*p++ & 0x80) {
|
||||
if (max < i + 1)
|
||||
return 0;
|
||||
/* Skip leading zeroes */
|
||||
while (i > 0 && *p == 0) {
|
||||
p++;
|
||||
i--;
|
||||
}
|
||||
if (i > (int)sizeof(long))
|
||||
return 0;
|
||||
while (i > 0) {
|
||||
ret <<= 8;
|
||||
ret |= *p++;
|
||||
i--;
|
||||
}
|
||||
if (ret > LONG_MAX)
|
||||
return 0;
|
||||
} else {
|
||||
ret = i;
|
||||
}
|
||||
}
|
||||
*pp = p;
|
||||
*rl = (long)ret;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* constructed == 2 for indefinite length constructed
|
||||
*/
|
||||
void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag,
|
||||
int xclass)
|
||||
{
|
||||
unsigned char *p = *pp;
|
||||
int i, ttag;
|
||||
|
||||
i = (constructed) ? V_ASN1_CONSTRUCTED : 0;
|
||||
i |= (xclass & V_ASN1_PRIVATE);
|
||||
if (tag < 31) {
|
||||
*(p++) = i | (tag & V_ASN1_PRIMITIVE_TAG);
|
||||
} else {
|
||||
*(p++) = i | V_ASN1_PRIMITIVE_TAG;
|
||||
for (i = 0, ttag = tag; ttag > 0; i++)
|
||||
ttag >>= 7;
|
||||
ttag = i;
|
||||
while (i-- > 0) {
|
||||
p[i] = tag & 0x7f;
|
||||
if (i != (ttag - 1))
|
||||
p[i] |= 0x80;
|
||||
tag >>= 7;
|
||||
}
|
||||
p += ttag;
|
||||
}
|
||||
if (constructed == 2)
|
||||
*(p++) = 0x80;
|
||||
else
|
||||
asn1_put_length(&p, length);
|
||||
*pp = p;
|
||||
}
|
||||
|
||||
int ASN1_put_eoc(unsigned char **pp)
|
||||
{
|
||||
unsigned char *p = *pp;
|
||||
|
||||
*p++ = 0;
|
||||
*p++ = 0;
|
||||
*pp = p;
|
||||
return 2;
|
||||
}
|
||||
|
||||
static void asn1_put_length(unsigned char **pp, int length)
|
||||
{
|
||||
unsigned char *p = *pp;
|
||||
int i, len;
|
||||
|
||||
if (length <= 127) {
|
||||
*(p++) = (unsigned char)length;
|
||||
} else {
|
||||
len = length;
|
||||
for (i = 0; len > 0; i++)
|
||||
len >>= 8;
|
||||
*(p++) = i | 0x80;
|
||||
len = i;
|
||||
while (i-- > 0) {
|
||||
p[i] = length & 0xff;
|
||||
length >>= 8;
|
||||
}
|
||||
p += len;
|
||||
}
|
||||
*pp = p;
|
||||
}
|
||||
|
||||
int ASN1_object_size(int constructed, int length, int tag)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if (length < 0)
|
||||
return -1;
|
||||
if (tag >= 31) {
|
||||
while (tag > 0) {
|
||||
tag >>= 7;
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
if (constructed == 2) {
|
||||
ret += 3;
|
||||
} else {
|
||||
ret++;
|
||||
if (length > 127) {
|
||||
int tmplen = length;
|
||||
while (tmplen > 0) {
|
||||
tmplen >>= 8;
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ret >= INT_MAX - length)
|
||||
return -1;
|
||||
return ret + length;
|
||||
}
|
||||
|
||||
void ossl_asn1_string_set_bits_left(ASN1_STRING *str, unsigned int num)
|
||||
{
|
||||
str->flags &= ~0x07;
|
||||
str->flags |= ASN1_STRING_FLAG_BITS_LEFT | (num & 0x07);
|
||||
}
|
||||
|
||||
int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str)
|
||||
{
|
||||
if (str == NULL)
|
||||
return 0;
|
||||
dst->type = str->type;
|
||||
if (!ASN1_STRING_set(dst, str->data, str->length))
|
||||
return 0;
|
||||
/* Copy flags but preserve embed value */
|
||||
dst->flags &= ASN1_STRING_FLAG_EMBED;
|
||||
dst->flags |= str->flags & ~ASN1_STRING_FLAG_EMBED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str)
|
||||
{
|
||||
ASN1_STRING *ret;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
ret = ASN1_STRING_new();
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
if (!ASN1_STRING_copy(ret, str)) {
|
||||
ASN1_STRING_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len_in)
|
||||
{
|
||||
unsigned char *c;
|
||||
const char *data = _data;
|
||||
size_t len;
|
||||
|
||||
if (len_in < 0) {
|
||||
if (data == NULL)
|
||||
return 0;
|
||||
len = strlen(data);
|
||||
} else {
|
||||
len = (size_t)len_in;
|
||||
}
|
||||
/*
|
||||
* Verify that the length fits within an integer for assignment to
|
||||
* str->length below. The additional 1 is subtracted to allow for the
|
||||
* '\0' terminator even though this isn't strictly necessary.
|
||||
*/
|
||||
if (len > INT_MAX - 1) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_TOO_LARGE);
|
||||
return 0;
|
||||
}
|
||||
if ((size_t)str->length <= len || str->data == NULL) {
|
||||
c = str->data;
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
/* No NUL terminator in fuzzing builds */
|
||||
str->data = OPENSSL_realloc(c, len != 0 ? len : 1);
|
||||
#else
|
||||
str->data = OPENSSL_realloc(c, len + 1);
|
||||
#endif
|
||||
if (str->data == NULL) {
|
||||
str->data = c;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
str->length = len;
|
||||
if (data != NULL) {
|
||||
memcpy(str->data, data, len);
|
||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||
/* Set the unused byte to something non NUL and printable. */
|
||||
if (len == 0)
|
||||
str->data[len] = '~';
|
||||
#else
|
||||
/*
|
||||
* Add a NUL terminator. This should not be necessary - but we add it as
|
||||
* a safety precaution
|
||||
*/
|
||||
str->data[len] = '\0';
|
||||
#endif
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len)
|
||||
{
|
||||
OPENSSL_free(str->data);
|
||||
str->data = data;
|
||||
str->length = len;
|
||||
}
|
||||
|
||||
ASN1_STRING *ASN1_STRING_new(void)
|
||||
{
|
||||
return ASN1_STRING_type_new(V_ASN1_OCTET_STRING);
|
||||
}
|
||||
|
||||
ASN1_STRING *ASN1_STRING_type_new(int type)
|
||||
{
|
||||
ASN1_STRING *ret;
|
||||
|
||||
ret = OPENSSL_zalloc(sizeof(*ret));
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
ret->type = type;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ossl_asn1_string_embed_free(ASN1_STRING *a, int embed)
|
||||
{
|
||||
if (a == NULL)
|
||||
return;
|
||||
if (!(a->flags & ASN1_STRING_FLAG_NDEF))
|
||||
OPENSSL_free(a->data);
|
||||
if (embed == 0)
|
||||
OPENSSL_free(a);
|
||||
}
|
||||
|
||||
void ASN1_STRING_free(ASN1_STRING *a)
|
||||
{
|
||||
if (a == NULL)
|
||||
return;
|
||||
ossl_asn1_string_embed_free(a, a->flags & ASN1_STRING_FLAG_EMBED);
|
||||
}
|
||||
|
||||
void ASN1_STRING_clear_free(ASN1_STRING *a)
|
||||
{
|
||||
if (a == NULL)
|
||||
return;
|
||||
if (a->data && !(a->flags & ASN1_STRING_FLAG_NDEF))
|
||||
OPENSSL_cleanse(a->data, a->length);
|
||||
ASN1_STRING_free(a);
|
||||
}
|
||||
|
||||
int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = (a->length - b->length);
|
||||
if (i == 0) {
|
||||
if (a->length != 0)
|
||||
i = memcmp(a->data, b->data, a->length);
|
||||
if (i == 0)
|
||||
return a->type - b->type;
|
||||
else
|
||||
return i;
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
int ASN1_STRING_length(const ASN1_STRING *x)
|
||||
{
|
||||
return x->length;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_3_0
|
||||
void ASN1_STRING_length_set(ASN1_STRING *x, int len)
|
||||
{
|
||||
x->length = len;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ASN1_STRING_type(const ASN1_STRING *x)
|
||||
{
|
||||
return x->type;
|
||||
}
|
||||
|
||||
const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x)
|
||||
{
|
||||
return x->data;
|
||||
}
|
||||
|
||||
#ifndef OPENSSL_NO_DEPRECATED_1_1_0
|
||||
unsigned char *ASN1_STRING_data(ASN1_STRING *x)
|
||||
{
|
||||
return x->data;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* |max_len| excludes NUL terminator and may be 0 to indicate no restriction */
|
||||
char *ossl_sk_ASN1_UTF8STRING2text(STACK_OF(ASN1_UTF8STRING) *text,
|
||||
const char *sep, size_t max_len)
|
||||
{
|
||||
int i;
|
||||
ASN1_UTF8STRING *current;
|
||||
size_t length = 0, sep_len;
|
||||
char *result = NULL;
|
||||
char *p;
|
||||
|
||||
if (sep == NULL)
|
||||
sep = "";
|
||||
sep_len = strlen(sep);
|
||||
|
||||
for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) {
|
||||
current = sk_ASN1_UTF8STRING_value(text, i);
|
||||
if (i > 0)
|
||||
length += sep_len;
|
||||
length += ASN1_STRING_length(current);
|
||||
if (max_len != 0 && length > max_len)
|
||||
return NULL;
|
||||
}
|
||||
if ((result = OPENSSL_malloc(length + 1)) == NULL)
|
||||
return NULL;
|
||||
|
||||
p = result;
|
||||
for (i = 0; i < sk_ASN1_UTF8STRING_num(text); i++) {
|
||||
current = sk_ASN1_UTF8STRING_value(text, i);
|
||||
length = ASN1_STRING_length(current);
|
||||
if (i > 0 && sep_len > 0) {
|
||||
strncpy(p, sep, sep_len + 1); /* using + 1 to silence gcc warning */
|
||||
p += sep_len;
|
||||
}
|
||||
strncpy(p, (const char *)ASN1_STRING_get0_data(current), length);
|
||||
p += length;
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* Internal ASN1 structures and functions: not for application use */
|
||||
|
||||
#include "crypto/asn1.h"
|
||||
|
||||
typedef const ASN1_VALUE const_ASN1_VALUE;
|
||||
SKM_DEFINE_STACK_OF(const_ASN1_VALUE, const ASN1_VALUE, ASN1_VALUE)
|
||||
|
||||
int ossl_asn1_time_to_tm(struct tm *tm, const ASN1_TIME *d);
|
||||
int ossl_asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
|
||||
|
||||
/* ASN1 scan context structure */
|
||||
|
||||
struct asn1_sctx_st {
|
||||
/* The ASN1_ITEM associated with this field */
|
||||
const ASN1_ITEM *it;
|
||||
/* If ASN1_TEMPLATE associated with this field */
|
||||
const ASN1_TEMPLATE *tt;
|
||||
/* Various flags associated with field and context */
|
||||
unsigned long flags;
|
||||
/* If SEQUENCE OF or SET OF, field index */
|
||||
int skidx;
|
||||
/* ASN1 depth of field */
|
||||
int depth;
|
||||
/* Structure and field name */
|
||||
const char *sname, *fname;
|
||||
/* If a primitive type the type of underlying field */
|
||||
int prim_type;
|
||||
/* The field value itself */
|
||||
ASN1_VALUE **field;
|
||||
/* Callback to pass information to */
|
||||
int (*scan_cb) (ASN1_SCTX *ctx);
|
||||
/* Context specific application data */
|
||||
void *app_data;
|
||||
} /* ASN1_SCTX */ ;
|
||||
|
||||
typedef struct mime_param_st MIME_PARAM;
|
||||
DEFINE_STACK_OF(MIME_PARAM)
|
||||
typedef struct mime_header_st MIME_HEADER;
|
||||
DEFINE_STACK_OF(MIME_HEADER)
|
||||
|
||||
void ossl_asn1_string_embed_free(ASN1_STRING *a, int embed);
|
||||
|
||||
int ossl_asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it);
|
||||
int ossl_asn1_get_choice_selector_const(const ASN1_VALUE **pval,
|
||||
const ASN1_ITEM *it);
|
||||
int ossl_asn1_set_choice_selector(ASN1_VALUE **pval, int value,
|
||||
const ASN1_ITEM *it);
|
||||
|
||||
ASN1_VALUE **ossl_asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
|
||||
const ASN1_VALUE **ossl_asn1_get_const_field_ptr(const ASN1_VALUE **pval,
|
||||
const ASN1_TEMPLATE *tt);
|
||||
|
||||
const ASN1_TEMPLATE *ossl_asn1_do_adb(const ASN1_VALUE *val,
|
||||
const ASN1_TEMPLATE *tt,
|
||||
int nullerr);
|
||||
|
||||
int ossl_asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it);
|
||||
|
||||
void ossl_asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it);
|
||||
void ossl_asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
|
||||
int ossl_asn1_enc_restore(int *len, unsigned char **out, const ASN1_VALUE **pval,
|
||||
const ASN1_ITEM *it);
|
||||
int ossl_asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
|
||||
const ASN1_ITEM *it);
|
||||
|
||||
void ossl_asn1_item_embed_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed);
|
||||
void ossl_asn1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int embed);
|
||||
void ossl_asn1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
|
||||
|
||||
ASN1_OBJECT *ossl_c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp,
|
||||
long length);
|
||||
int ossl_i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp);
|
||||
ASN1_BIT_STRING *ossl_c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,
|
||||
const unsigned char **pp, long length);
|
||||
int ossl_i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp);
|
||||
ASN1_INTEGER *ossl_c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp,
|
||||
long length);
|
||||
|
||||
/* Internal functions used by x_int64.c */
|
||||
int ossl_c2i_uint64_int(uint64_t *ret, int *neg, const unsigned char **pp,
|
||||
long len);
|
||||
int ossl_i2c_uint64_int(unsigned char *p, uint64_t r, int neg);
|
||||
|
||||
ASN1_TIME *ossl_asn1_time_from_tm(ASN1_TIME *s, struct tm *ts, int type);
|
||||
|
||||
int ossl_asn1_item_ex_new_intern(ASN1_VALUE **pval, const ASN1_ITEM *it,
|
||||
OSSL_LIB_CTX *libctx, const char *propq);
|
||||
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
* Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
#ifndef ASN1_PARSE_MAXDEPTH
|
||||
#define ASN1_PARSE_MAXDEPTH 128
|
||||
#endif
|
||||
|
||||
static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
|
||||
int offset, int depth, int indent, int dump);
|
||||
static int asn1_print_info(BIO *bp, long offset, int depth, int hl, long len,
|
||||
int tag, int xclass, int constructed, int indent)
|
||||
{
|
||||
char str[128];
|
||||
const char *p;
|
||||
int pop_f_prefix = 0;
|
||||
long saved_indent = -1;
|
||||
int i = 0;
|
||||
BIO *bio = NULL;
|
||||
|
||||
if (constructed & V_ASN1_CONSTRUCTED)
|
||||
p = "cons: ";
|
||||
else
|
||||
p = "prim: ";
|
||||
if (constructed != (V_ASN1_CONSTRUCTED | 1)) {
|
||||
if (BIO_snprintf(str, sizeof(str), "%5ld:d=%-2d hl=%ld l=%4ld %s",
|
||||
offset, depth, (long)hl, len, p) <= 0)
|
||||
goto err;
|
||||
} else {
|
||||
if (BIO_snprintf(str, sizeof(str), "%5ld:d=%-2d hl=%ld l=inf %s",
|
||||
offset, depth, (long)hl, p) <= 0)
|
||||
goto err;
|
||||
}
|
||||
if (bp != NULL) {
|
||||
if (BIO_set_prefix(bp, str) <= 0) {
|
||||
if ((bio = BIO_new(BIO_f_prefix())) == NULL
|
||||
|| (bp = BIO_push(bio, bp)) == NULL)
|
||||
goto err;
|
||||
pop_f_prefix = 1;
|
||||
}
|
||||
saved_indent = BIO_get_indent(bp);
|
||||
if (BIO_set_prefix(bp, str) <= 0 || BIO_set_indent(bp, indent) <= 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* BIO_set_prefix made a copy of |str|, so we can safely use it for
|
||||
* something else, ASN.1 tag printout.
|
||||
*/
|
||||
p = str;
|
||||
if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE)
|
||||
BIO_snprintf(str, sizeof(str), "priv [ %d ] ", tag);
|
||||
else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC)
|
||||
BIO_snprintf(str, sizeof(str), "cont [ %d ]", tag);
|
||||
else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION)
|
||||
BIO_snprintf(str, sizeof(str), "appl [ %d ]", tag);
|
||||
else if (tag > 30)
|
||||
BIO_snprintf(str, sizeof(str), "<ASN1 %d>", tag);
|
||||
else
|
||||
p = ASN1_tag2str(tag);
|
||||
|
||||
i = (BIO_printf(bp, "%-18s", p) > 0);
|
||||
err:
|
||||
if (saved_indent >= 0)
|
||||
BIO_set_indent(bp, saved_indent);
|
||||
if (pop_f_prefix)
|
||||
BIO_pop(bp);
|
||||
BIO_free(bio);
|
||||
return i;
|
||||
}
|
||||
|
||||
int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent)
|
||||
{
|
||||
return asn1_parse2(bp, &pp, len, 0, 0, indent, 0);
|
||||
}
|
||||
|
||||
int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent,
|
||||
int dump)
|
||||
{
|
||||
return asn1_parse2(bp, &pp, len, 0, 0, indent, dump);
|
||||
}
|
||||
|
||||
static int asn1_parse2(BIO *bp, const unsigned char **pp, long length,
|
||||
int offset, int depth, int indent, int dump)
|
||||
{
|
||||
const unsigned char *p, *ep, *tot, *op, *opp;
|
||||
long len;
|
||||
int tag, xclass, ret = 0;
|
||||
int nl, hl, j, r;
|
||||
ASN1_OBJECT *o = NULL;
|
||||
ASN1_OCTET_STRING *os = NULL;
|
||||
ASN1_INTEGER *ai = NULL;
|
||||
ASN1_ENUMERATED *ae = NULL;
|
||||
/* ASN1_BMPSTRING *bmp=NULL; */
|
||||
int dump_indent, dump_cont = 0;
|
||||
|
||||
if (depth > ASN1_PARSE_MAXDEPTH) {
|
||||
BIO_puts(bp, "BAD RECURSION DEPTH\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
dump_indent = 6; /* Because we know BIO_dump_indent() */
|
||||
p = *pp;
|
||||
tot = p + length;
|
||||
while (length > 0) {
|
||||
op = p;
|
||||
j = ASN1_get_object(&p, &len, &tag, &xclass, length);
|
||||
if (j & 0x80) {
|
||||
BIO_puts(bp, "Error in encoding\n");
|
||||
goto end;
|
||||
}
|
||||
hl = (p - op);
|
||||
length -= hl;
|
||||
/*
|
||||
* if j == 0x21 it is a constructed indefinite length object
|
||||
*/
|
||||
if (!asn1_print_info(bp, (long)offset + (long)(op - *pp), depth,
|
||||
hl, len, tag, xclass, j, (indent) ? depth : 0))
|
||||
goto end;
|
||||
if (j & V_ASN1_CONSTRUCTED) {
|
||||
const unsigned char *sp = p;
|
||||
|
||||
ep = p + len;
|
||||
if (BIO_write(bp, "\n", 1) <= 0)
|
||||
goto end;
|
||||
if (len > length) {
|
||||
BIO_printf(bp, "length is greater than %ld\n", length);
|
||||
goto end;
|
||||
}
|
||||
if ((j == 0x21) && (len == 0)) {
|
||||
for (;;) {
|
||||
r = asn1_parse2(bp, &p, (long)(tot - p),
|
||||
offset + (p - *pp), depth + 1,
|
||||
indent, dump);
|
||||
if (r == 0)
|
||||
goto end;
|
||||
if ((r == 2) || (p >= tot)) {
|
||||
len = p - sp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
long tmp = len;
|
||||
|
||||
while (p < ep) {
|
||||
sp = p;
|
||||
r = asn1_parse2(bp, &p, tmp,
|
||||
offset + (p - *pp), depth + 1,
|
||||
indent, dump);
|
||||
if (r == 0)
|
||||
goto end;
|
||||
tmp -= p - sp;
|
||||
}
|
||||
}
|
||||
} else if (xclass != 0) {
|
||||
p += len;
|
||||
if (BIO_write(bp, "\n", 1) <= 0)
|
||||
goto end;
|
||||
} else {
|
||||
nl = 0;
|
||||
if ((tag == V_ASN1_PRINTABLESTRING) ||
|
||||
(tag == V_ASN1_T61STRING) ||
|
||||
(tag == V_ASN1_IA5STRING) ||
|
||||
(tag == V_ASN1_VISIBLESTRING) ||
|
||||
(tag == V_ASN1_NUMERICSTRING) ||
|
||||
(tag == V_ASN1_UTF8STRING) ||
|
||||
(tag == V_ASN1_UTCTIME) || (tag == V_ASN1_GENERALIZEDTIME)) {
|
||||
if (BIO_write(bp, ":", 1) <= 0)
|
||||
goto end;
|
||||
if ((len > 0) && BIO_write(bp, (const char *)p, (int)len)
|
||||
!= (int)len)
|
||||
goto end;
|
||||
} else if (tag == V_ASN1_OBJECT) {
|
||||
opp = op;
|
||||
if (d2i_ASN1_OBJECT(&o, &opp, len + hl) != NULL) {
|
||||
if (BIO_write(bp, ":", 1) <= 0)
|
||||
goto end;
|
||||
i2a_ASN1_OBJECT(bp, o);
|
||||
} else {
|
||||
if (BIO_puts(bp, ":BAD OBJECT") <= 0)
|
||||
goto end;
|
||||
dump_cont = 1;
|
||||
}
|
||||
} else if (tag == V_ASN1_BOOLEAN) {
|
||||
if (len != 1) {
|
||||
if (BIO_puts(bp, ":BAD BOOLEAN") <= 0)
|
||||
goto end;
|
||||
dump_cont = 1;
|
||||
}
|
||||
if (len > 0)
|
||||
BIO_printf(bp, ":%u", p[0]);
|
||||
} else if (tag == V_ASN1_BMPSTRING) {
|
||||
/* do the BMP thang */
|
||||
} else if (tag == V_ASN1_OCTET_STRING) {
|
||||
int i, printable = 1;
|
||||
|
||||
opp = op;
|
||||
os = d2i_ASN1_OCTET_STRING(NULL, &opp, len + hl);
|
||||
if (os != NULL && os->length > 0) {
|
||||
opp = os->data;
|
||||
/*
|
||||
* testing whether the octet string is printable
|
||||
*/
|
||||
for (i = 0; i < os->length; i++) {
|
||||
if (((opp[i] < ' ') &&
|
||||
(opp[i] != '\n') &&
|
||||
(opp[i] != '\r') &&
|
||||
(opp[i] != '\t')) || (opp[i] > '~')) {
|
||||
printable = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (printable)
|
||||
/* printable string */
|
||||
{
|
||||
if (BIO_write(bp, ":", 1) <= 0)
|
||||
goto end;
|
||||
if (BIO_write(bp, (const char *)opp, os->length) <= 0)
|
||||
goto end;
|
||||
} else if (!dump)
|
||||
/*
|
||||
* not printable => print octet string as hex dump
|
||||
*/
|
||||
{
|
||||
if (BIO_write(bp, "[HEX DUMP]:", 11) <= 0)
|
||||
goto end;
|
||||
for (i = 0; i < os->length; i++) {
|
||||
if (BIO_printf(bp, "%02X", opp[i]) <= 0)
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
/* print the normal dump */
|
||||
{
|
||||
if (!nl) {
|
||||
if (BIO_write(bp, "\n", 1) <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (BIO_dump_indent(bp,
|
||||
(const char *)opp,
|
||||
((dump == -1 || dump >
|
||||
os->
|
||||
length) ? os->length : dump),
|
||||
dump_indent) <= 0)
|
||||
goto end;
|
||||
nl = 1;
|
||||
}
|
||||
}
|
||||
ASN1_OCTET_STRING_free(os);
|
||||
os = NULL;
|
||||
} else if (tag == V_ASN1_INTEGER) {
|
||||
int i;
|
||||
|
||||
opp = op;
|
||||
ai = d2i_ASN1_INTEGER(NULL, &opp, len + hl);
|
||||
if (ai != NULL) {
|
||||
if (BIO_write(bp, ":", 1) <= 0)
|
||||
goto end;
|
||||
if (ai->type == V_ASN1_NEG_INTEGER)
|
||||
if (BIO_write(bp, "-", 1) <= 0)
|
||||
goto end;
|
||||
for (i = 0; i < ai->length; i++) {
|
||||
if (BIO_printf(bp, "%02X", ai->data[i]) <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (ai->length == 0) {
|
||||
if (BIO_write(bp, "00", 2) <= 0)
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (BIO_puts(bp, ":BAD INTEGER") <= 0)
|
||||
goto end;
|
||||
dump_cont = 1;
|
||||
}
|
||||
ASN1_INTEGER_free(ai);
|
||||
ai = NULL;
|
||||
} else if (tag == V_ASN1_ENUMERATED) {
|
||||
int i;
|
||||
|
||||
opp = op;
|
||||
ae = d2i_ASN1_ENUMERATED(NULL, &opp, len + hl);
|
||||
if (ae != NULL) {
|
||||
if (BIO_write(bp, ":", 1) <= 0)
|
||||
goto end;
|
||||
if (ae->type == V_ASN1_NEG_ENUMERATED)
|
||||
if (BIO_write(bp, "-", 1) <= 0)
|
||||
goto end;
|
||||
for (i = 0; i < ae->length; i++) {
|
||||
if (BIO_printf(bp, "%02X", ae->data[i]) <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (ae->length == 0) {
|
||||
if (BIO_write(bp, "00", 2) <= 0)
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
if (BIO_puts(bp, ":BAD ENUMERATED") <= 0)
|
||||
goto end;
|
||||
dump_cont = 1;
|
||||
}
|
||||
ASN1_ENUMERATED_free(ae);
|
||||
ae = NULL;
|
||||
} else if (len > 0 && dump) {
|
||||
if (!nl) {
|
||||
if (BIO_write(bp, "\n", 1) <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (BIO_dump_indent(bp, (const char *)p,
|
||||
((dump == -1 || dump > len) ? len : dump),
|
||||
dump_indent) <= 0)
|
||||
goto end;
|
||||
nl = 1;
|
||||
}
|
||||
if (dump_cont) {
|
||||
int i;
|
||||
const unsigned char *tmp = op + hl;
|
||||
if (BIO_puts(bp, ":[") <= 0)
|
||||
goto end;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (BIO_printf(bp, "%02X", tmp[i]) <= 0)
|
||||
goto end;
|
||||
}
|
||||
if (BIO_puts(bp, "]") <= 0)
|
||||
goto end;
|
||||
dump_cont = 0;
|
||||
}
|
||||
|
||||
if (!nl) {
|
||||
if (BIO_write(bp, "\n", 1) <= 0)
|
||||
goto end;
|
||||
}
|
||||
p += len;
|
||||
if ((tag == V_ASN1_EOC) && (xclass == 0)) {
|
||||
ret = 2; /* End of sequence */
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
length -= len;
|
||||
}
|
||||
ret = 1;
|
||||
end:
|
||||
ASN1_OBJECT_free(o);
|
||||
ASN1_OCTET_STRING_free(os);
|
||||
ASN1_INTEGER_free(ai);
|
||||
ASN1_ENUMERATED_free(ae);
|
||||
*pp = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *ASN1_tag2str(int tag)
|
||||
{
|
||||
static const char *const tag2str[] = {
|
||||
/* 0-4 */
|
||||
"EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING",
|
||||
/* 5-9 */
|
||||
"NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL",
|
||||
/* 10-13 */
|
||||
"ENUMERATED", "<ASN1 11>", "UTF8STRING", "<ASN1 13>",
|
||||
/* 15-17 */
|
||||
"<ASN1 14>", "<ASN1 15>", "SEQUENCE", "SET",
|
||||
/* 18-20 */
|
||||
"NUMERICSTRING", "PRINTABLESTRING", "T61STRING",
|
||||
/* 21-24 */
|
||||
"VIDEOTEXSTRING", "IA5STRING", "UTCTIME", "GENERALIZEDTIME",
|
||||
/* 25-27 */
|
||||
"GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING",
|
||||
/* 28-30 */
|
||||
"UNIVERSALSTRING", "<ASN1 29>", "BMPSTRING"
|
||||
};
|
||||
|
||||
if ((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED))
|
||||
tag &= ~0x100;
|
||||
|
||||
if (tag < 0 || tag > 30)
|
||||
return "(unknown)";
|
||||
return tag2str[tag];
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "crypto/ctype.h"
|
||||
#include <openssl/crypto.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/x509.h>
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/objects.h"
|
||||
|
||||
/* Simple ASN1 OID module: add all objects in a given section */
|
||||
|
||||
static int do_create(const char *value, const char *name);
|
||||
|
||||
static int oid_module_init(CONF_IMODULE *md, const CONF *cnf)
|
||||
{
|
||||
int i;
|
||||
const char *oid_section;
|
||||
STACK_OF(CONF_VALUE) *sktmp;
|
||||
CONF_VALUE *oval;
|
||||
|
||||
oid_section = CONF_imodule_get_value(md);
|
||||
if ((sktmp = NCONF_get_section(cnf, oid_section)) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ERROR_LOADING_SECTION);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
|
||||
oval = sk_CONF_VALUE_value(sktmp, i);
|
||||
if (!do_create(oval->value, oval->name)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ADDING_OBJECT);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void oid_module_finish(CONF_IMODULE *md)
|
||||
{
|
||||
}
|
||||
|
||||
void ASN1_add_oid_module(void)
|
||||
{
|
||||
CONF_module_add("oid_section", oid_module_init, oid_module_finish);
|
||||
}
|
||||
|
||||
/*-
|
||||
* Create an OID based on a name value pair. Accept two formats.
|
||||
* shortname = 1.2.3.4
|
||||
* shortname = some long name, 1.2.3.4
|
||||
*/
|
||||
|
||||
static int do_create(const char *value, const char *name)
|
||||
{
|
||||
int nid;
|
||||
const char *ln, *ostr, *p;
|
||||
char *lntmp = NULL;
|
||||
|
||||
p = strrchr(value, ',');
|
||||
if (p == NULL) {
|
||||
ln = name;
|
||||
ostr = value;
|
||||
} else if (p == value) {
|
||||
/* we started with a leading comma */
|
||||
ln = name;
|
||||
ostr = p + 1;
|
||||
} else {
|
||||
ln = value;
|
||||
ostr = p + 1;
|
||||
if (*ostr == '\0')
|
||||
return 0;
|
||||
while (ossl_isspace(*ostr))
|
||||
ostr++;
|
||||
while (ossl_isspace(*ln))
|
||||
ln++;
|
||||
p--;
|
||||
while (ossl_isspace(*p)) {
|
||||
if (p == ln)
|
||||
return 0;
|
||||
p--;
|
||||
}
|
||||
p++;
|
||||
if ((lntmp = OPENSSL_malloc((p - ln) + 1)) == NULL)
|
||||
return 0;
|
||||
memcpy(lntmp, ln, p - ln);
|
||||
lntmp[p - ln] = '\0';
|
||||
ln = lntmp;
|
||||
}
|
||||
|
||||
nid = OBJ_create(ostr, name, ln);
|
||||
|
||||
OPENSSL_free(lntmp);
|
||||
|
||||
return nid != NID_undef;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2012-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
/* Multi string module: add table entries from a given section */
|
||||
|
||||
static int do_tcreate(const char *value, const char *name);
|
||||
|
||||
static int stbl_module_init(CONF_IMODULE *md, const CONF *cnf)
|
||||
{
|
||||
int i;
|
||||
const char *stbl_section;
|
||||
STACK_OF(CONF_VALUE) *sktmp;
|
||||
CONF_VALUE *mval;
|
||||
|
||||
stbl_section = CONF_imodule_get_value(md);
|
||||
if ((sktmp = NCONF_get_section(cnf, stbl_section)) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ERROR_LOADING_SECTION);
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < sk_CONF_VALUE_num(sktmp); i++) {
|
||||
mval = sk_CONF_VALUE_value(sktmp, i);
|
||||
if (!do_tcreate(mval->value, mval->name)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_INVALID_VALUE);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void stbl_module_finish(CONF_IMODULE *md)
|
||||
{
|
||||
ASN1_STRING_TABLE_cleanup();
|
||||
}
|
||||
|
||||
void ASN1_add_stable_module(void)
|
||||
{
|
||||
CONF_module_add("stbl_section", stbl_module_init, stbl_module_finish);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an table entry based on a name value pair. format is oid_name =
|
||||
* n1:v1, n2:v2,... where name is "min", "max", "mask" or "flags".
|
||||
*/
|
||||
|
||||
static int do_tcreate(const char *value, const char *name)
|
||||
{
|
||||
char *eptr;
|
||||
int nid, i, rv = 0;
|
||||
long tbl_min = -1, tbl_max = -1;
|
||||
unsigned long tbl_mask = 0, tbl_flags = 0;
|
||||
STACK_OF(CONF_VALUE) *lst = NULL;
|
||||
CONF_VALUE *cnf = NULL;
|
||||
nid = OBJ_sn2nid(name);
|
||||
if (nid == NID_undef)
|
||||
nid = OBJ_ln2nid(name);
|
||||
if (nid == NID_undef)
|
||||
goto err;
|
||||
lst = X509V3_parse_list(value);
|
||||
if (!lst)
|
||||
goto err;
|
||||
for (i = 0; i < sk_CONF_VALUE_num(lst); i++) {
|
||||
cnf = sk_CONF_VALUE_value(lst, i);
|
||||
if (cnf->value == NULL)
|
||||
goto err;
|
||||
if (strcmp(cnf->name, "min") == 0) {
|
||||
tbl_min = strtoul(cnf->value, &eptr, 0);
|
||||
if (*eptr)
|
||||
goto err;
|
||||
} else if (strcmp(cnf->name, "max") == 0) {
|
||||
tbl_max = strtoul(cnf->value, &eptr, 0);
|
||||
if (*eptr)
|
||||
goto err;
|
||||
} else if (strcmp(cnf->name, "mask") == 0) {
|
||||
if (!ASN1_str2mask(cnf->value, &tbl_mask) || !tbl_mask)
|
||||
goto err;
|
||||
} else if (strcmp(cnf->name, "flags") == 0) {
|
||||
if (strcmp(cnf->value, "nomask") == 0)
|
||||
tbl_flags = STABLE_NO_MASK;
|
||||
else if (strcmp(cnf->value, "none") == 0)
|
||||
tbl_flags = STABLE_FLAGS_CLEAR;
|
||||
else
|
||||
goto err;
|
||||
} else
|
||||
goto err;
|
||||
}
|
||||
rv = 1;
|
||||
err:
|
||||
if (rv == 0) {
|
||||
if (cnf)
|
||||
ERR_raise_data(ERR_LIB_ASN1, ASN1_R_INVALID_STRING_TABLE_VALUE,
|
||||
"field=%s, value=%s", cnf->name,
|
||||
cnf->value != NULL ? cnf->value
|
||||
: value);
|
||||
else
|
||||
ERR_raise_data(ERR_LIB_ASN1, ASN1_R_INVALID_STRING_TABLE_VALUE,
|
||||
"name=%s, value=%s", name, value);
|
||||
} else {
|
||||
rv = ASN1_STRING_TABLE_add(nid, tbl_min, tbl_max,
|
||||
tbl_mask, tbl_flags);
|
||||
if (!rv)
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
}
|
||||
sk_CONF_VALUE_pop_free(lst, X509V3_conf_free);
|
||||
return rv;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
/* ASN1 packing and unpacking functions */
|
||||
|
||||
ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_STRING **oct)
|
||||
{
|
||||
ASN1_STRING *octmp;
|
||||
|
||||
if (oct == NULL || *oct == NULL) {
|
||||
if ((octmp = ASN1_STRING_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
octmp = *oct;
|
||||
}
|
||||
|
||||
ASN1_STRING_set0(octmp, NULL, 0);
|
||||
|
||||
if ((octmp->length = ASN1_item_i2d(obj, &octmp->data, it)) <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ENCODE_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if (octmp->data == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (oct != NULL && *oct == NULL)
|
||||
*oct = octmp;
|
||||
|
||||
return octmp;
|
||||
err:
|
||||
if (oct == NULL || *oct == NULL)
|
||||
ASN1_STRING_free(octmp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Extract an ASN1 object from an ASN1_STRING */
|
||||
|
||||
void *ASN1_item_unpack(const ASN1_STRING *oct, const ASN1_ITEM *it)
|
||||
{
|
||||
const unsigned char *p;
|
||||
void *ret;
|
||||
|
||||
p = oct->data;
|
||||
if ((ret = ASN1_item_d2i(NULL, &p, oct->length, it)) == NULL)
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_DECODE_ERROR);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *ASN1_item_unpack_ex(const ASN1_STRING *oct, const ASN1_ITEM *it,
|
||||
OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
const unsigned char *p;
|
||||
void *ret;
|
||||
|
||||
p = oct->data;
|
||||
if ((ret = ASN1_item_d2i_ex(NULL, &p, oct->length, it,\
|
||||
libctx, propq)) == NULL)
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_DECODE_ERROR);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* Copyright 2006-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Experimental ASN1 BIO. When written through the data is converted to an
|
||||
* ASN1 string type: default is OCTET STRING. Additional functions can be
|
||||
* provided to add prefix and suffix data.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "internal/bio.h"
|
||||
#include <openssl/asn1.h>
|
||||
#include "internal/cryptlib.h"
|
||||
|
||||
/* Must be large enough for biggest tag+length */
|
||||
#define DEFAULT_ASN1_BUF_SIZE 20
|
||||
|
||||
typedef enum {
|
||||
ASN1_STATE_START,
|
||||
ASN1_STATE_PRE_COPY,
|
||||
ASN1_STATE_HEADER,
|
||||
ASN1_STATE_HEADER_COPY,
|
||||
ASN1_STATE_DATA_COPY,
|
||||
ASN1_STATE_POST_COPY,
|
||||
ASN1_STATE_DONE
|
||||
} asn1_bio_state_t;
|
||||
|
||||
typedef struct BIO_ASN1_EX_FUNCS_st {
|
||||
asn1_ps_func *ex_func;
|
||||
asn1_ps_func *ex_free_func;
|
||||
} BIO_ASN1_EX_FUNCS;
|
||||
|
||||
typedef struct BIO_ASN1_BUF_CTX_t {
|
||||
/* Internal state */
|
||||
asn1_bio_state_t state;
|
||||
/* Internal buffer */
|
||||
unsigned char *buf;
|
||||
/* Size of buffer */
|
||||
int bufsize;
|
||||
/* Current position in buffer */
|
||||
int bufpos;
|
||||
/* Current buffer length */
|
||||
int buflen;
|
||||
/* Amount of data to copy */
|
||||
int copylen;
|
||||
/* Class and tag to use */
|
||||
int asn1_class, asn1_tag;
|
||||
asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
|
||||
/* Extra buffer for prefix and suffix data */
|
||||
unsigned char *ex_buf;
|
||||
int ex_len;
|
||||
int ex_pos;
|
||||
void *ex_arg;
|
||||
} BIO_ASN1_BUF_CTX;
|
||||
|
||||
static int asn1_bio_write(BIO *h, const char *buf, int num);
|
||||
static int asn1_bio_read(BIO *h, char *buf, int size);
|
||||
static int asn1_bio_puts(BIO *h, const char *str);
|
||||
static int asn1_bio_gets(BIO *h, char *str, int size);
|
||||
static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
|
||||
static int asn1_bio_new(BIO *h);
|
||||
static int asn1_bio_free(BIO *data);
|
||||
static long asn1_bio_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
|
||||
|
||||
static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
|
||||
static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
|
||||
asn1_ps_func *cleanup, asn1_bio_state_t next);
|
||||
static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
|
||||
asn1_ps_func *setup,
|
||||
asn1_bio_state_t ex_state,
|
||||
asn1_bio_state_t other_state);
|
||||
|
||||
static const BIO_METHOD methods_asn1 = {
|
||||
BIO_TYPE_ASN1,
|
||||
"asn1",
|
||||
bwrite_conv,
|
||||
asn1_bio_write,
|
||||
bread_conv,
|
||||
asn1_bio_read,
|
||||
asn1_bio_puts,
|
||||
asn1_bio_gets,
|
||||
asn1_bio_ctrl,
|
||||
asn1_bio_new,
|
||||
asn1_bio_free,
|
||||
asn1_bio_callback_ctrl,
|
||||
};
|
||||
|
||||
const BIO_METHOD *BIO_f_asn1(void)
|
||||
{
|
||||
return &methods_asn1;
|
||||
}
|
||||
|
||||
static int asn1_bio_new(BIO *b)
|
||||
{
|
||||
BIO_ASN1_BUF_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx));
|
||||
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) {
|
||||
OPENSSL_free(ctx);
|
||||
return 0;
|
||||
}
|
||||
BIO_set_data(b, ctx);
|
||||
BIO_set_init(b, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
|
||||
{
|
||||
if (size <= 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
if ((ctx->buf = OPENSSL_malloc(size)) == NULL)
|
||||
return 0;
|
||||
ctx->bufsize = size;
|
||||
ctx->asn1_class = V_ASN1_UNIVERSAL;
|
||||
ctx->asn1_tag = V_ASN1_OCTET_STRING;
|
||||
ctx->state = ASN1_STATE_START;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_bio_free(BIO *b)
|
||||
{
|
||||
BIO_ASN1_BUF_CTX *ctx;
|
||||
|
||||
if (b == NULL)
|
||||
return 0;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
|
||||
if (ctx->prefix_free != NULL)
|
||||
ctx->prefix_free(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
|
||||
if (ctx->suffix_free != NULL)
|
||||
ctx->suffix_free(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
|
||||
|
||||
OPENSSL_free(ctx->buf);
|
||||
OPENSSL_free(ctx);
|
||||
BIO_set_data(b, NULL);
|
||||
BIO_set_init(b, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_bio_write(BIO *b, const char *in, int inl)
|
||||
{
|
||||
BIO_ASN1_BUF_CTX *ctx;
|
||||
int wrmax, wrlen, ret;
|
||||
unsigned char *p;
|
||||
BIO *next;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
next = BIO_next(b);
|
||||
if (in == NULL || inl < 0 || ctx == NULL || next == NULL)
|
||||
return 0;
|
||||
|
||||
wrlen = 0;
|
||||
ret = -1;
|
||||
|
||||
for (;;) {
|
||||
switch (ctx->state) {
|
||||
/* Setup prefix data, call it */
|
||||
case ASN1_STATE_START:
|
||||
if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
|
||||
ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
/* Copy any pre data first */
|
||||
case ASN1_STATE_PRE_COPY:
|
||||
|
||||
ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
|
||||
ASN1_STATE_HEADER);
|
||||
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
|
||||
case ASN1_STATE_HEADER:
|
||||
ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
|
||||
if (!ossl_assert(ctx->buflen <= ctx->bufsize))
|
||||
return -1;
|
||||
p = ctx->buf;
|
||||
ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class);
|
||||
ctx->copylen = inl;
|
||||
ctx->state = ASN1_STATE_HEADER_COPY;
|
||||
|
||||
break;
|
||||
|
||||
case ASN1_STATE_HEADER_COPY:
|
||||
ret = BIO_write(next, ctx->buf + ctx->bufpos, ctx->buflen);
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
|
||||
ctx->buflen -= ret;
|
||||
if (ctx->buflen)
|
||||
ctx->bufpos += ret;
|
||||
else {
|
||||
ctx->bufpos = 0;
|
||||
ctx->state = ASN1_STATE_DATA_COPY;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ASN1_STATE_DATA_COPY:
|
||||
|
||||
if (inl > ctx->copylen)
|
||||
wrmax = ctx->copylen;
|
||||
else
|
||||
wrmax = inl;
|
||||
ret = BIO_write(next, in, wrmax);
|
||||
if (ret <= 0)
|
||||
goto done;
|
||||
wrlen += ret;
|
||||
ctx->copylen -= ret;
|
||||
in += ret;
|
||||
inl -= ret;
|
||||
|
||||
if (ctx->copylen == 0)
|
||||
ctx->state = ASN1_STATE_HEADER;
|
||||
|
||||
if (inl == 0)
|
||||
goto done;
|
||||
|
||||
break;
|
||||
|
||||
case ASN1_STATE_POST_COPY:
|
||||
case ASN1_STATE_DONE:
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
done:
|
||||
BIO_clear_retry_flags(b);
|
||||
BIO_copy_next_retry(b);
|
||||
|
||||
return (wrlen > 0) ? wrlen : ret;
|
||||
|
||||
}
|
||||
|
||||
static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
|
||||
asn1_ps_func *cleanup, asn1_bio_state_t next)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ctx->ex_len <= 0)
|
||||
return 1;
|
||||
for (;;) {
|
||||
ret = BIO_write(BIO_next(b), ctx->ex_buf + ctx->ex_pos, ctx->ex_len);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ctx->ex_len -= ret;
|
||||
if (ctx->ex_len > 0)
|
||||
ctx->ex_pos += ret;
|
||||
else {
|
||||
if (cleanup)
|
||||
cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
|
||||
ctx->state = next;
|
||||
ctx->ex_pos = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
|
||||
asn1_ps_func *setup,
|
||||
asn1_bio_state_t ex_state,
|
||||
asn1_bio_state_t other_state)
|
||||
{
|
||||
if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
if (ctx->ex_len > 0)
|
||||
ctx->state = ex_state;
|
||||
else
|
||||
ctx->state = other_state;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int asn1_bio_read(BIO *b, char *in, int inl)
|
||||
{
|
||||
BIO *next = BIO_next(b);
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
return BIO_read(next, in, inl);
|
||||
}
|
||||
|
||||
static int asn1_bio_puts(BIO *b, const char *str)
|
||||
{
|
||||
return asn1_bio_write(b, str, strlen(str));
|
||||
}
|
||||
|
||||
static int asn1_bio_gets(BIO *b, char *str, int size)
|
||||
{
|
||||
BIO *next = BIO_next(b);
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
return BIO_gets(next, str, size);
|
||||
}
|
||||
|
||||
static long asn1_bio_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
|
||||
{
|
||||
BIO *next = BIO_next(b);
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
return BIO_callback_ctrl(next, cmd, fp);
|
||||
}
|
||||
|
||||
static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
|
||||
{
|
||||
BIO_ASN1_BUF_CTX *ctx;
|
||||
BIO_ASN1_EX_FUNCS *ex_func;
|
||||
long ret = 1;
|
||||
BIO *next;
|
||||
|
||||
ctx = BIO_get_data(b);
|
||||
if (ctx == NULL)
|
||||
return 0;
|
||||
next = BIO_next(b);
|
||||
switch (cmd) {
|
||||
|
||||
case BIO_C_SET_PREFIX:
|
||||
ex_func = arg2;
|
||||
ctx->prefix = ex_func->ex_func;
|
||||
ctx->prefix_free = ex_func->ex_free_func;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_PREFIX:
|
||||
ex_func = arg2;
|
||||
ex_func->ex_func = ctx->prefix;
|
||||
ex_func->ex_free_func = ctx->prefix_free;
|
||||
break;
|
||||
|
||||
case BIO_C_SET_SUFFIX:
|
||||
ex_func = arg2;
|
||||
ctx->suffix = ex_func->ex_func;
|
||||
ctx->suffix_free = ex_func->ex_free_func;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_SUFFIX:
|
||||
ex_func = arg2;
|
||||
ex_func->ex_func = ctx->suffix;
|
||||
ex_func->ex_free_func = ctx->suffix_free;
|
||||
break;
|
||||
|
||||
case BIO_C_SET_EX_ARG:
|
||||
ctx->ex_arg = arg2;
|
||||
break;
|
||||
|
||||
case BIO_C_GET_EX_ARG:
|
||||
*(void **)arg2 = ctx->ex_arg;
|
||||
break;
|
||||
|
||||
case BIO_CTRL_FLUSH:
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
|
||||
/* Call post function if possible */
|
||||
if (ctx->state == ASN1_STATE_HEADER) {
|
||||
if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
|
||||
ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->state == ASN1_STATE_POST_COPY) {
|
||||
ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
|
||||
ASN1_STATE_DONE);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ctx->state == ASN1_STATE_DONE)
|
||||
return BIO_ctrl(next, cmd, arg1, arg2);
|
||||
else {
|
||||
BIO_clear_retry_flags(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
if (next == NULL)
|
||||
return 0;
|
||||
return BIO_ctrl(next, cmd, arg1, arg2);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int asn1_bio_set_ex(BIO *b, int cmd,
|
||||
asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
|
||||
{
|
||||
BIO_ASN1_EX_FUNCS extmp;
|
||||
extmp.ex_func = ex_func;
|
||||
extmp.ex_free_func = ex_free_func;
|
||||
return BIO_ctrl(b, cmd, 0, &extmp);
|
||||
}
|
||||
|
||||
static int asn1_bio_get_ex(BIO *b, int cmd,
|
||||
asn1_ps_func **ex_func,
|
||||
asn1_ps_func **ex_free_func)
|
||||
{
|
||||
BIO_ASN1_EX_FUNCS extmp;
|
||||
int ret;
|
||||
ret = BIO_ctrl(b, cmd, 0, &extmp);
|
||||
if (ret > 0) {
|
||||
*ex_func = extmp.ex_func;
|
||||
*ex_free_func = extmp.ex_free_func;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
|
||||
asn1_ps_func *prefix_free)
|
||||
{
|
||||
return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
|
||||
}
|
||||
|
||||
int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
|
||||
asn1_ps_func **pprefix_free)
|
||||
{
|
||||
return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
|
||||
}
|
||||
|
||||
int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
|
||||
asn1_ps_func *suffix_free)
|
||||
{
|
||||
return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
|
||||
}
|
||||
|
||||
int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
|
||||
asn1_ps_func **psuffix_free)
|
||||
{
|
||||
return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* Copyright 2008-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Experimental NDEF ASN1 BIO support routines */
|
||||
|
||||
/*
|
||||
* The usage is quite simple, initialize an ASN1 structure, get a BIO from it
|
||||
* then any data written through the BIO will end up translated to
|
||||
* appropriate format on the fly. The data is streamed out and does *not*
|
||||
* need to be all held in memory at once. When the BIO is flushed the output
|
||||
* is finalized and any signatures etc written out. The BIO is a 'proper'
|
||||
* BIO and can handle non blocking I/O correctly. The usage is simple. The
|
||||
* implementation is *not*...
|
||||
*/
|
||||
|
||||
/* BIO support data stored in the ASN1 BIO ex_arg */
|
||||
|
||||
typedef struct ndef_aux_st {
|
||||
/* ASN1 structure this BIO refers to */
|
||||
ASN1_VALUE *val;
|
||||
const ASN1_ITEM *it;
|
||||
/* Top of the BIO chain */
|
||||
BIO *ndef_bio;
|
||||
/* Output BIO */
|
||||
BIO *out;
|
||||
/* Boundary where content is inserted */
|
||||
unsigned char **boundary;
|
||||
/* DER buffer start */
|
||||
unsigned char *derbuf;
|
||||
} NDEF_SUPPORT;
|
||||
|
||||
static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
|
||||
static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
|
||||
void *parg);
|
||||
static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
|
||||
static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
|
||||
void *parg);
|
||||
|
||||
/*
|
||||
* On success, the returned BIO owns the input BIO as part of its BIO chain.
|
||||
* On failure, NULL is returned and the input BIO is owned by the caller.
|
||||
*
|
||||
* Unfortunately cannot constify this due to CMS_stream() and PKCS7_stream()
|
||||
*/
|
||||
BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
|
||||
{
|
||||
NDEF_SUPPORT *ndef_aux = NULL;
|
||||
BIO *asn_bio = NULL;
|
||||
const ASN1_AUX *aux = it->funcs;
|
||||
ASN1_STREAM_ARG sarg;
|
||||
BIO *pop_bio = NULL;
|
||||
|
||||
if (!aux || !aux->asn1_cb) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
|
||||
return NULL;
|
||||
}
|
||||
ndef_aux = OPENSSL_zalloc(sizeof(*ndef_aux));
|
||||
asn_bio = BIO_new(BIO_f_asn1());
|
||||
if (ndef_aux == NULL || asn_bio == NULL)
|
||||
goto err;
|
||||
|
||||
/* ASN1 bio needs to be next to output BIO */
|
||||
out = BIO_push(asn_bio, out);
|
||||
if (out == NULL)
|
||||
goto err;
|
||||
pop_bio = asn_bio;
|
||||
|
||||
if (BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free) <= 0
|
||||
|| BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free) <= 0
|
||||
|| BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux) <= 0)
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Now let the callback prepend any digest, cipher, etc., that the BIO's
|
||||
* ASN1 structure needs.
|
||||
*/
|
||||
|
||||
sarg.out = out;
|
||||
sarg.ndef_bio = NULL;
|
||||
sarg.boundary = NULL;
|
||||
|
||||
/*
|
||||
* The asn1_cb(), must not have mutated asn_bio on error, leaving it in the
|
||||
* middle of some partially built, but not returned BIO chain.
|
||||
*/
|
||||
if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) {
|
||||
/*
|
||||
* ndef_aux is now owned by asn_bio so we must not free it in the err
|
||||
* clean up block
|
||||
*/
|
||||
ndef_aux = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* We must not fail now because the callback has prepended additional
|
||||
* BIOs to the chain
|
||||
*/
|
||||
|
||||
ndef_aux->val = val;
|
||||
ndef_aux->it = it;
|
||||
ndef_aux->ndef_bio = sarg.ndef_bio;
|
||||
ndef_aux->boundary = sarg.boundary;
|
||||
ndef_aux->out = out;
|
||||
|
||||
return sarg.ndef_bio;
|
||||
|
||||
err:
|
||||
/* BIO_pop() is NULL safe */
|
||||
(void)BIO_pop(pop_bio);
|
||||
BIO_free(asn_bio);
|
||||
OPENSSL_free(ndef_aux);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
|
||||
{
|
||||
NDEF_SUPPORT *ndef_aux;
|
||||
unsigned char *p;
|
||||
int derlen;
|
||||
|
||||
if (parg == NULL)
|
||||
return 0;
|
||||
|
||||
ndef_aux = *(NDEF_SUPPORT **)parg;
|
||||
|
||||
derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
|
||||
if (derlen < 0)
|
||||
return 0;
|
||||
if ((p = OPENSSL_malloc(derlen)) == NULL)
|
||||
return 0;
|
||||
|
||||
ndef_aux->derbuf = p;
|
||||
*pbuf = p;
|
||||
ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
|
||||
|
||||
if (*ndef_aux->boundary == NULL)
|
||||
return 0;
|
||||
|
||||
*plen = *ndef_aux->boundary - *pbuf;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
|
||||
void *parg)
|
||||
{
|
||||
NDEF_SUPPORT *ndef_aux;
|
||||
|
||||
if (parg == NULL)
|
||||
return 0;
|
||||
|
||||
ndef_aux = *(NDEF_SUPPORT **)parg;
|
||||
|
||||
if (ndef_aux == NULL)
|
||||
return 0;
|
||||
|
||||
OPENSSL_free(ndef_aux->derbuf);
|
||||
|
||||
ndef_aux->derbuf = NULL;
|
||||
*pbuf = NULL;
|
||||
*plen = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
|
||||
void *parg)
|
||||
{
|
||||
NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
|
||||
if (!ndef_prefix_free(b, pbuf, plen, parg))
|
||||
return 0;
|
||||
OPENSSL_free(*pndef_aux);
|
||||
*pndef_aux = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
|
||||
{
|
||||
NDEF_SUPPORT *ndef_aux;
|
||||
unsigned char *p;
|
||||
int derlen;
|
||||
const ASN1_AUX *aux;
|
||||
ASN1_STREAM_ARG sarg;
|
||||
|
||||
if (parg == NULL)
|
||||
return 0;
|
||||
|
||||
ndef_aux = *(NDEF_SUPPORT **)parg;
|
||||
|
||||
aux = ndef_aux->it->funcs;
|
||||
|
||||
/* Finalize structures */
|
||||
sarg.ndef_bio = ndef_aux->ndef_bio;
|
||||
sarg.out = ndef_aux->out;
|
||||
sarg.boundary = ndef_aux->boundary;
|
||||
if (aux->asn1_cb(ASN1_OP_STREAM_POST,
|
||||
&ndef_aux->val, ndef_aux->it, &sarg) <= 0)
|
||||
return 0;
|
||||
|
||||
derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
|
||||
if (derlen < 0)
|
||||
return 0;
|
||||
if ((p = OPENSSL_malloc(derlen)) == NULL)
|
||||
return 0;
|
||||
|
||||
ndef_aux->derbuf = p;
|
||||
*pbuf = p;
|
||||
derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
|
||||
|
||||
if (*ndef_aux->boundary == NULL)
|
||||
return 0;
|
||||
*pbuf = *ndef_aux->boundary;
|
||||
*plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
LIBS=../../libcrypto
|
||||
SOURCE[../../libcrypto]=\
|
||||
a_object.c a_bitstr.c a_utctm.c a_gentm.c a_time.c a_int.c a_octet.c \
|
||||
a_print.c a_type.c a_dup.c a_d2i_fp.c a_i2d_fp.c \
|
||||
a_utf8.c a_sign.c a_digest.c a_verify.c a_mbstr.c a_strex.c \
|
||||
x_algor.c x_val.c x_sig.c x_bignum.c \
|
||||
x_int64.c x_info.c x_spki.c nsseq.c \
|
||||
d2i_pu.c d2i_pr.c i2d_evp.c \
|
||||
t_pkey.c t_spki.c t_bitst.c \
|
||||
tasn_new.c tasn_fre.c tasn_enc.c tasn_dec.c tasn_utl.c tasn_typ.c \
|
||||
tasn_prn.c tasn_scn.c ameth_lib.c \
|
||||
f_int.c f_string.c \
|
||||
x_pkey.c bio_asn1.c bio_ndef.c asn_mime.c \
|
||||
asn1_gen.c asn1_parse.c asn1_lib.c asn1_err.c a_strnid.c \
|
||||
evp_asn1.c asn_pack.c p5_pbe.c p5_pbev2.c p5_scrypt.c p8_pkey.c \
|
||||
asn_moid.c asn_mstbl.c asn1_item_list.c \
|
||||
d2i_param.c
|
||||
IF[{- !$disabled{'rsa'} and !$disabled{'rc4'} -}]
|
||||
SOURCE[../../libcrypto]=n_pkey.c
|
||||
ENDIF
|
||||
IF[{- !$disabled{'deprecated-3.0'} -}]
|
||||
SOURCE[../../libcrypto]=x_long.c
|
||||
ENDIF
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* WARNING: do not edit!
|
||||
* Generated by crypto/asn1/charmap.pl
|
||||
*
|
||||
* Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#define CHARTYPE_HOST_ANY 4096
|
||||
#define CHARTYPE_HOST_DOT 8192
|
||||
#define CHARTYPE_HOST_HYPHEN 16384
|
||||
#define CHARTYPE_HOST_WILD 32768
|
||||
|
||||
/*
|
||||
* Mask of various character properties
|
||||
*/
|
||||
|
||||
static const unsigned short char_type[] = {
|
||||
1026, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 120, 0, 1, 40,
|
||||
0, 0, 0, 16, 1040, 1040, 33792, 25, 25, 16400, 8208, 16,
|
||||
4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 16, 9,
|
||||
9, 16, 9, 16, 0, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
|
||||
4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
|
||||
4112, 4112, 4112, 4112, 4112, 4112, 4112, 0, 1025, 0, 0, 0,
|
||||
0, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
|
||||
4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112, 4112,
|
||||
4112, 4112, 4112, 0, 0, 0, 0, 2
|
||||
};
|
||||
@@ -0,0 +1,123 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
use strict;
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../../util/perl";
|
||||
use OpenSSL::copyright;
|
||||
|
||||
my ($i, @arr);
|
||||
|
||||
# Set up an array with the type of ASCII characters
|
||||
# Each set bit represents a character property.
|
||||
|
||||
# RFC2253 character properties
|
||||
my $RFC2253_ESC = 1; # Character escaped with \
|
||||
my $ESC_CTRL = 2; # Escaped control character
|
||||
# These are used with RFC1779 quoting using "
|
||||
my $NOESC_QUOTE = 8; # Not escaped if quoted
|
||||
my $PSTRING_CHAR = 0x10; # Valid PrintableString character
|
||||
my $RFC2253_FIRST_ESC = 0x20; # Escaped with \ if first character
|
||||
my $RFC2253_LAST_ESC = 0x40; # Escaped with \ if last character
|
||||
my $RFC2254_ESC = 0x400; # Character escaped \XX
|
||||
my $HOST_ANY = 0x1000; # Valid hostname character anywhere in label
|
||||
my $HOST_DOT = 0x2000; # Dot: hostname label separator
|
||||
my $HOST_HYPHEN = 0x4000; # Hyphen: not valid at start or end.
|
||||
my $HOST_WILD = 0x8000; # Wildcard character
|
||||
|
||||
for($i = 0; $i < 128; $i++) {
|
||||
# Set the RFC2253 escape characters (control)
|
||||
$arr[$i] = 0;
|
||||
if(($i < 32) || ($i > 126)) {
|
||||
$arr[$i] |= $ESC_CTRL;
|
||||
}
|
||||
|
||||
# Some PrintableString characters
|
||||
if( ( ( $i >= ord("a")) && ( $i <= ord("z")) )
|
||||
|| ( ( $i >= ord("A")) && ( $i <= ord("Z")) )
|
||||
|| ( ( $i >= ord("0")) && ( $i <= ord("9")) ) ) {
|
||||
$arr[$i] |= $PSTRING_CHAR | $HOST_ANY;
|
||||
}
|
||||
}
|
||||
|
||||
# Now setup the rest
|
||||
|
||||
# Remaining RFC2253 escaped characters
|
||||
|
||||
$arr[ord(" ")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC | $RFC2253_LAST_ESC;
|
||||
$arr[ord("#")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC;
|
||||
|
||||
$arr[ord(",")] |= $NOESC_QUOTE | $RFC2253_ESC;
|
||||
$arr[ord("+")] |= $NOESC_QUOTE | $RFC2253_ESC;
|
||||
$arr[ord("\"")] |= $RFC2253_ESC;
|
||||
$arr[ord("\\")] |= $RFC2253_ESC;
|
||||
$arr[ord("<")] |= $NOESC_QUOTE | $RFC2253_ESC;
|
||||
$arr[ord(">")] |= $NOESC_QUOTE | $RFC2253_ESC;
|
||||
$arr[ord(";")] |= $NOESC_QUOTE | $RFC2253_ESC;
|
||||
|
||||
# Remaining RFC2254 characters
|
||||
|
||||
$arr[0] |= $RFC2254_ESC;
|
||||
$arr[ord("(")] |= $RFC2254_ESC;
|
||||
$arr[ord(")")] |= $RFC2254_ESC;
|
||||
$arr[ord("*")] |= $RFC2254_ESC | $HOST_WILD;
|
||||
$arr[ord("\\")] |= $RFC2254_ESC;
|
||||
|
||||
# Remaining PrintableString characters
|
||||
|
||||
$arr[ord(" ")] |= $PSTRING_CHAR;
|
||||
$arr[ord("'")] |= $PSTRING_CHAR;
|
||||
$arr[ord("(")] |= $PSTRING_CHAR;
|
||||
$arr[ord(")")] |= $PSTRING_CHAR;
|
||||
$arr[ord("+")] |= $PSTRING_CHAR;
|
||||
$arr[ord(",")] |= $PSTRING_CHAR;
|
||||
$arr[ord("-")] |= $PSTRING_CHAR | $HOST_HYPHEN;
|
||||
$arr[ord(".")] |= $PSTRING_CHAR | $HOST_DOT;
|
||||
$arr[ord("/")] |= $PSTRING_CHAR;
|
||||
$arr[ord(":")] |= $PSTRING_CHAR;
|
||||
$arr[ord("=")] |= $PSTRING_CHAR;
|
||||
$arr[ord("?")] |= $PSTRING_CHAR;
|
||||
|
||||
# Now generate the C code
|
||||
|
||||
# Year the file was generated.
|
||||
my $YEAR = OpenSSL::copyright::year_of($0);
|
||||
|
||||
print <<EOF;
|
||||
/*
|
||||
* WARNING: do not edit!
|
||||
* Generated by crypto/asn1/charmap.pl
|
||||
*
|
||||
* Copyright 2000-$YEAR The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#define CHARTYPE_HOST_ANY $HOST_ANY
|
||||
#define CHARTYPE_HOST_DOT $HOST_DOT
|
||||
#define CHARTYPE_HOST_HYPHEN $HOST_HYPHEN
|
||||
#define CHARTYPE_HOST_WILD $HOST_WILD
|
||||
|
||||
/*
|
||||
* Mask of various character properties
|
||||
*/
|
||||
|
||||
static const unsigned short char_type[] = {
|
||||
EOF
|
||||
|
||||
print " ";
|
||||
for($i = 0; $i < 128; $i++) {
|
||||
print("\n ") if($i && (($i % 12) == 0));
|
||||
printf(" %4d", $arr[$i]);
|
||||
print(",") if ($i != 127);
|
||||
}
|
||||
print("\n};\n");
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include "internal/asn1.h"
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/evp.h"
|
||||
|
||||
EVP_PKEY *d2i_KeyParams(int type, EVP_PKEY **a, const unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
EVP_PKEY *ret = NULL;
|
||||
|
||||
if ((a == NULL) || (*a == NULL)) {
|
||||
if ((ret = EVP_PKEY_new()) == NULL)
|
||||
return NULL;
|
||||
} else
|
||||
ret = *a;
|
||||
|
||||
if (type != EVP_PKEY_get_id(ret) && !EVP_PKEY_set_type(ret, type))
|
||||
goto err;
|
||||
|
||||
if (ret->ameth == NULL || ret->ameth->param_decode == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_TYPE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ret->ameth->param_decode(ret, pp, length))
|
||||
goto err;
|
||||
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
return ret;
|
||||
err:
|
||||
if (a == NULL || *a != ret)
|
||||
EVP_PKEY_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY *d2i_KeyParams_bio(int type, EVP_PKEY **a, BIO *in)
|
||||
{
|
||||
BUF_MEM *b = NULL;
|
||||
const unsigned char *p;
|
||||
void *ret = NULL;
|
||||
int len;
|
||||
|
||||
len = asn1_d2i_read_bio(in, &b);
|
||||
if (len < 0)
|
||||
goto err;
|
||||
|
||||
p = (unsigned char *)b->data;
|
||||
ret = d2i_KeyParams(type, a, &p, len);
|
||||
err:
|
||||
BUF_MEM_free(b);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/* We need to use some engine deprecated APIs */
|
||||
#define OPENSSL_SUPPRESS_DEPRECATED
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/decoder.h>
|
||||
#include <openssl/engine.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include "crypto/asn1.h"
|
||||
#include "crypto/evp.h"
|
||||
#include "crypto/x509.h"
|
||||
#include "internal/asn1.h"
|
||||
#include "internal/sizes.h"
|
||||
|
||||
static EVP_PKEY *
|
||||
d2i_PrivateKey_decoder(int keytype, EVP_PKEY **a, const unsigned char **pp,
|
||||
long length, OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
OSSL_DECODER_CTX *dctx = NULL;
|
||||
size_t len = length;
|
||||
EVP_PKEY *pkey = NULL, *bak_a = NULL;
|
||||
EVP_PKEY **ppkey = &pkey;
|
||||
const char *key_name = NULL;
|
||||
char keytypebuf[OSSL_MAX_NAME_SIZE];
|
||||
int ret;
|
||||
const unsigned char *p = *pp;
|
||||
const char *structure;
|
||||
PKCS8_PRIV_KEY_INFO *p8info;
|
||||
const ASN1_OBJECT *algoid;
|
||||
|
||||
if (keytype != EVP_PKEY_NONE) {
|
||||
key_name = evp_pkey_type2name(keytype);
|
||||
if (key_name == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is just a probe. It might fail, so we ignore errors */
|
||||
ERR_set_mark();
|
||||
p8info = d2i_PKCS8_PRIV_KEY_INFO(NULL, pp, len);
|
||||
ERR_pop_to_mark();
|
||||
if (p8info != NULL) {
|
||||
int64_t v;
|
||||
|
||||
/* ascertain version is 0 or 1 as per RFC5958 */
|
||||
if (!ASN1_INTEGER_get_int64(&v, p8info->version)
|
||||
|| (v != 0 && v != 1)) {
|
||||
*pp = p;
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ASN1_PARSE_ERROR);
|
||||
PKCS8_PRIV_KEY_INFO_free(p8info);
|
||||
return NULL;
|
||||
}
|
||||
if (key_name == NULL
|
||||
&& PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8info)
|
||||
&& OBJ_obj2txt(keytypebuf, sizeof(keytypebuf), algoid, 0))
|
||||
key_name = keytypebuf;
|
||||
structure = "PrivateKeyInfo";
|
||||
PKCS8_PRIV_KEY_INFO_free(p8info);
|
||||
} else {
|
||||
structure = "type-specific";
|
||||
}
|
||||
*pp = p;
|
||||
|
||||
if (a != NULL && (bak_a = *a) != NULL)
|
||||
ppkey = a;
|
||||
dctx = OSSL_DECODER_CTX_new_for_pkey(ppkey, "DER", structure, key_name,
|
||||
EVP_PKEY_KEYPAIR, libctx, propq);
|
||||
if (a != NULL)
|
||||
*a = bak_a;
|
||||
if (dctx == NULL)
|
||||
goto err;
|
||||
|
||||
ret = OSSL_DECODER_from_data(dctx, pp, &len);
|
||||
OSSL_DECODER_CTX_free(dctx);
|
||||
if (ret
|
||||
&& *ppkey != NULL
|
||||
&& evp_keymgmt_util_has(*ppkey, OSSL_KEYMGMT_SELECT_PRIVATE_KEY)) {
|
||||
if (a != NULL)
|
||||
*a = *ppkey;
|
||||
return *ppkey;
|
||||
}
|
||||
|
||||
err:
|
||||
if (ppkey != a)
|
||||
EVP_PKEY_free(*ppkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY *
|
||||
ossl_d2i_PrivateKey_legacy(int keytype, EVP_PKEY **a, const unsigned char **pp,
|
||||
long length, OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
EVP_PKEY *ret;
|
||||
const unsigned char *p = *pp;
|
||||
|
||||
if (a == NULL || *a == NULL) {
|
||||
if ((ret = EVP_PKEY_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
ret = *a;
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
ENGINE_finish(ret->engine);
|
||||
ret->engine = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!EVP_PKEY_set_type(ret, keytype)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ERR_set_mark();
|
||||
if (!ret->ameth->old_priv_decode ||
|
||||
!ret->ameth->old_priv_decode(ret, &p, length)) {
|
||||
if (ret->ameth->priv_decode != NULL
|
||||
|| ret->ameth->priv_decode_ex != NULL) {
|
||||
EVP_PKEY *tmp;
|
||||
PKCS8_PRIV_KEY_INFO *p8 = NULL;
|
||||
p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, length);
|
||||
if (p8 == NULL) {
|
||||
ERR_clear_last_mark();
|
||||
goto err;
|
||||
}
|
||||
tmp = evp_pkcs82pkey_legacy(p8, libctx, propq);
|
||||
PKCS8_PRIV_KEY_INFO_free(p8);
|
||||
if (tmp == NULL) {
|
||||
ERR_clear_last_mark();
|
||||
goto err;
|
||||
}
|
||||
EVP_PKEY_free(ret);
|
||||
ret = tmp;
|
||||
ERR_pop_to_mark();
|
||||
if (EVP_PKEY_type(keytype) != EVP_PKEY_get_base_id(ret))
|
||||
goto err;
|
||||
} else {
|
||||
ERR_clear_last_mark();
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
ERR_clear_last_mark();
|
||||
}
|
||||
*pp = p;
|
||||
if (a != NULL)
|
||||
*a = ret;
|
||||
return ret;
|
||||
err:
|
||||
if (a == NULL || *a != ret)
|
||||
EVP_PKEY_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EVP_PKEY *d2i_PrivateKey_ex(int keytype, EVP_PKEY **a, const unsigned char **pp,
|
||||
long length, OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
EVP_PKEY *ret;
|
||||
|
||||
ret = d2i_PrivateKey_decoder(keytype, a, pp, length, libctx, propq);
|
||||
/* try the legacy path if the decoder failed */
|
||||
if (ret == NULL)
|
||||
ret = ossl_d2i_PrivateKey_legacy(keytype, a, pp, length, libctx, propq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
return d2i_PrivateKey_ex(type, a, pp, length, NULL, NULL);
|
||||
}
|
||||
|
||||
static EVP_PKEY *d2i_AutoPrivateKey_legacy(EVP_PKEY **a,
|
||||
const unsigned char **pp,
|
||||
long length,
|
||||
OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
STACK_OF(ASN1_TYPE) *inkey;
|
||||
const unsigned char *p;
|
||||
int keytype;
|
||||
|
||||
p = *pp;
|
||||
/*
|
||||
* Dirty trick: read in the ASN1 data into a STACK_OF(ASN1_TYPE): by
|
||||
* analyzing it we can determine the passed structure: this assumes the
|
||||
* input is surrounded by an ASN1 SEQUENCE.
|
||||
*/
|
||||
inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, length);
|
||||
p = *pp;
|
||||
/*
|
||||
* Since we only need to discern "traditional format" RSA and DSA keys we
|
||||
* can just count the elements.
|
||||
*/
|
||||
if (sk_ASN1_TYPE_num(inkey) == 6) {
|
||||
keytype = EVP_PKEY_DSA;
|
||||
} else if (sk_ASN1_TYPE_num(inkey) == 4) {
|
||||
keytype = EVP_PKEY_EC;
|
||||
} else if (sk_ASN1_TYPE_num(inkey) == 3) { /* This seems to be PKCS8, not
|
||||
* traditional format */
|
||||
PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, length);
|
||||
EVP_PKEY *ret;
|
||||
|
||||
sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
|
||||
if (p8 == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
|
||||
return NULL;
|
||||
}
|
||||
ret = evp_pkcs82pkey_legacy(p8, libctx, propq);
|
||||
PKCS8_PRIV_KEY_INFO_free(p8);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
*pp = p;
|
||||
if (a != NULL) {
|
||||
*a = ret;
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
keytype = EVP_PKEY_RSA;
|
||||
}
|
||||
sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free);
|
||||
return ossl_d2i_PrivateKey_legacy(keytype, a, pp, length, libctx, propq);
|
||||
}
|
||||
|
||||
/*
|
||||
* This works like d2i_PrivateKey() except it passes the keytype as
|
||||
* EVP_PKEY_NONE, which then figures out the type during decoding.
|
||||
*/
|
||||
EVP_PKEY *d2i_AutoPrivateKey_ex(EVP_PKEY **a, const unsigned char **pp,
|
||||
long length, OSSL_LIB_CTX *libctx,
|
||||
const char *propq)
|
||||
{
|
||||
EVP_PKEY *ret;
|
||||
|
||||
ret = d2i_PrivateKey_decoder(EVP_PKEY_NONE, a, pp, length, libctx, propq);
|
||||
/* try the legacy path if the decoder failed */
|
||||
if (ret == NULL)
|
||||
ret = d2i_AutoPrivateKey_legacy(a, pp, length, libctx, propq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
return d2i_AutoPrivateKey_ex(a, pp, length, NULL, NULL);
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* DSA low level APIs are deprecated for public use, but still ok for
|
||||
* internal use.
|
||||
*/
|
||||
#include "internal/deprecated.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/dsa.h>
|
||||
#include <openssl/ec.h>
|
||||
|
||||
#include "crypto/evp.h"
|
||||
|
||||
EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp,
|
||||
long length)
|
||||
{
|
||||
EVP_PKEY *ret;
|
||||
EVP_PKEY *copy = NULL;
|
||||
|
||||
if ((a == NULL) || (*a == NULL)) {
|
||||
if ((ret = EVP_PKEY_new()) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
ret = *a;
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
if (evp_pkey_is_provided(ret)
|
||||
&& EVP_PKEY_get_base_id(ret) == EVP_PKEY_EC) {
|
||||
if (!evp_pkey_copy_downgraded(©, ret))
|
||||
goto err;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((type != EVP_PKEY_get_id(ret) || copy != NULL)
|
||||
&& !EVP_PKEY_set_type(ret, type)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB);
|
||||
goto err;
|
||||
}
|
||||
|
||||
switch (EVP_PKEY_get_base_id(ret)) {
|
||||
case EVP_PKEY_RSA:
|
||||
if ((ret->pkey.rsa = d2i_RSAPublicKey(NULL, pp, length)) == NULL) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
#ifndef OPENSSL_NO_DSA
|
||||
case EVP_PKEY_DSA:
|
||||
if (!d2i_DSAPublicKey(&ret->pkey.dsa, pp, length)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_EC
|
||||
case EVP_PKEY_EC:
|
||||
if (copy != NULL) {
|
||||
/* use downgraded parameters from copy */
|
||||
ret->pkey.ec = copy->pkey.ec;
|
||||
copy->pkey.ec = NULL;
|
||||
}
|
||||
if (!o2i_ECPublicKey(&ret->pkey.ec, pp, length)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB);
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE);
|
||||
goto err;
|
||||
}
|
||||
if (a != NULL)
|
||||
(*a) = ret;
|
||||
EVP_PKEY_free(copy);
|
||||
return ret;
|
||||
err:
|
||||
if (a == NULL || *a != ret)
|
||||
EVP_PKEY_free(ret);
|
||||
EVP_PKEY_free(copy);
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/asn1t.h>
|
||||
#include "crypto/asn1.h"
|
||||
|
||||
int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len)
|
||||
{
|
||||
ASN1_STRING *os;
|
||||
|
||||
if ((os = ASN1_OCTET_STRING_new()) == NULL)
|
||||
return 0;
|
||||
if (!ASN1_OCTET_STRING_set(os, data, len)) {
|
||||
ASN1_OCTET_STRING_free(os);
|
||||
return 0;
|
||||
}
|
||||
ASN1_TYPE_set(a, V_ASN1_OCTET_STRING, os);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* int max_len: for returned value
|
||||
* if passing NULL in data, nothing is copied but the necessary length
|
||||
* for it is returned.
|
||||
*/
|
||||
int ASN1_TYPE_get_octetstring(const ASN1_TYPE *a, unsigned char *data, int max_len)
|
||||
{
|
||||
int ret, num;
|
||||
const unsigned char *p;
|
||||
|
||||
if ((a->type != V_ASN1_OCTET_STRING) || (a->value.octet_string == NULL)) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_DATA_IS_WRONG);
|
||||
return -1;
|
||||
}
|
||||
p = ASN1_STRING_get0_data(a->value.octet_string);
|
||||
ret = ASN1_STRING_length(a->value.octet_string);
|
||||
if (ret < max_len)
|
||||
num = ret;
|
||||
else
|
||||
num = max_len;
|
||||
if (num > 0 && data != NULL)
|
||||
memcpy(data, p, num);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ossl_inline void asn1_type_init_oct(ASN1_OCTET_STRING *oct,
|
||||
unsigned char *data, int len)
|
||||
{
|
||||
oct->data = data;
|
||||
oct->type = V_ASN1_OCTET_STRING;
|
||||
oct->length = len;
|
||||
oct->flags = 0;
|
||||
}
|
||||
|
||||
static int asn1_type_get_int_oct(ASN1_OCTET_STRING *oct, int32_t anum,
|
||||
long *num, unsigned char *data, int max_len)
|
||||
{
|
||||
int ret = ASN1_STRING_length(oct), n;
|
||||
|
||||
if (num != NULL)
|
||||
*num = anum;
|
||||
|
||||
if (max_len > ret)
|
||||
n = ret;
|
||||
else
|
||||
n = max_len;
|
||||
|
||||
if (data != NULL)
|
||||
memcpy(data, ASN1_STRING_get0_data(oct), n);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int32_t num;
|
||||
ASN1_OCTET_STRING *oct;
|
||||
} asn1_int_oct;
|
||||
|
||||
ASN1_SEQUENCE(asn1_int_oct) = {
|
||||
ASN1_EMBED(asn1_int_oct, num, INT32),
|
||||
ASN1_SIMPLE(asn1_int_oct, oct, ASN1_OCTET_STRING)
|
||||
} static_ASN1_SEQUENCE_END(asn1_int_oct)
|
||||
|
||||
DECLARE_ASN1_ITEM(asn1_int_oct)
|
||||
|
||||
int ASN1_TYPE_set_int_octetstring(ASN1_TYPE *a, long num, unsigned char *data,
|
||||
int len)
|
||||
{
|
||||
asn1_int_oct atmp;
|
||||
ASN1_OCTET_STRING oct;
|
||||
|
||||
atmp.num = num;
|
||||
atmp.oct = &oct;
|
||||
asn1_type_init_oct(&oct, data, len);
|
||||
|
||||
if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(asn1_int_oct), &atmp, &a))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num,
|
||||
unsigned char *data, int max_len)
|
||||
{
|
||||
asn1_int_oct *atmp = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if ((a->type != V_ASN1_SEQUENCE) || (a->value.sequence == NULL)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
atmp = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(asn1_int_oct), a);
|
||||
|
||||
if (atmp == NULL)
|
||||
goto err;
|
||||
|
||||
ret = asn1_type_get_int_oct(atmp->oct, atmp->num, num, data, max_len);
|
||||
|
||||
if (ret == -1) {
|
||||
err:
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_DATA_IS_WRONG);
|
||||
}
|
||||
M_ASN1_free_of(atmp, asn1_int_oct);
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ASN1_OCTET_STRING *oct;
|
||||
int32_t num;
|
||||
} asn1_oct_int;
|
||||
|
||||
/*
|
||||
* Defined in RFC 5084 -
|
||||
* Section 2. "Content-Authenticated Encryption Algorithms"
|
||||
*/
|
||||
ASN1_SEQUENCE(asn1_oct_int) = {
|
||||
ASN1_SIMPLE(asn1_oct_int, oct, ASN1_OCTET_STRING),
|
||||
ASN1_EMBED(asn1_oct_int, num, INT32)
|
||||
} static_ASN1_SEQUENCE_END(asn1_oct_int)
|
||||
|
||||
DECLARE_ASN1_ITEM(asn1_oct_int)
|
||||
|
||||
int ossl_asn1_type_set_octetstring_int(ASN1_TYPE *a, long num,
|
||||
unsigned char *data, int len)
|
||||
{
|
||||
asn1_oct_int atmp;
|
||||
ASN1_OCTET_STRING oct;
|
||||
|
||||
atmp.num = num;
|
||||
atmp.oct = &oct;
|
||||
asn1_type_init_oct(&oct, data, len);
|
||||
|
||||
if (ASN1_TYPE_pack_sequence(ASN1_ITEM_rptr(asn1_oct_int), &atmp, &a))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ossl_asn1_type_get_octetstring_int(const ASN1_TYPE *a, long *num,
|
||||
unsigned char *data, int max_len)
|
||||
{
|
||||
asn1_oct_int *atmp = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if ((a->type != V_ASN1_SEQUENCE) || (a->value.sequence == NULL))
|
||||
goto err;
|
||||
|
||||
atmp = ASN1_TYPE_unpack_sequence(ASN1_ITEM_rptr(asn1_oct_int), a);
|
||||
|
||||
if (atmp == NULL)
|
||||
goto err;
|
||||
|
||||
ret = asn1_type_get_int_oct(atmp->oct, atmp->num, num, data, max_len);
|
||||
|
||||
if (ret == -1) {
|
||||
err:
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_DATA_IS_WRONG);
|
||||
}
|
||||
M_ASN1_free_of(atmp, asn1_oct_int);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "crypto/ctype.h"
|
||||
#include "internal/cryptlib.h"
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/asn1.h>
|
||||
|
||||
int i2a_ASN1_INTEGER(BIO *bp, const ASN1_INTEGER *a)
|
||||
{
|
||||
int i, n = 0;
|
||||
char buf[2];
|
||||
|
||||
if (a == NULL)
|
||||
return 0;
|
||||
|
||||
if (a->type & V_ASN1_NEG) {
|
||||
if (BIO_write(bp, "-", 1) != 1)
|
||||
goto err;
|
||||
n = 1;
|
||||
}
|
||||
|
||||
if (a->length == 0) {
|
||||
if (BIO_write(bp, "00", 2) != 2)
|
||||
goto err;
|
||||
n += 2;
|
||||
} else {
|
||||
for (i = 0; i < a->length; i++) {
|
||||
if ((i != 0) && (i % 35 == 0)) {
|
||||
if (BIO_write(bp, "\\\n", 2) != 2)
|
||||
goto err;
|
||||
n += 2;
|
||||
}
|
||||
ossl_to_hex(buf, a->data[i]);
|
||||
if (BIO_write(bp, buf, 2) != 2)
|
||||
goto err;
|
||||
n += 2;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size)
|
||||
{
|
||||
int i, j, k, m, n, again, bufsize;
|
||||
unsigned char *s = NULL, *sp;
|
||||
unsigned char *bufp;
|
||||
int num = 0, slen = 0, first = 1;
|
||||
|
||||
bs->type = V_ASN1_INTEGER;
|
||||
|
||||
bufsize = BIO_gets(bp, buf, size);
|
||||
for (;;) {
|
||||
if (bufsize < 1)
|
||||
goto err;
|
||||
i = bufsize;
|
||||
if (buf[i - 1] == '\n')
|
||||
buf[--i] = '\0';
|
||||
if (i == 0)
|
||||
goto err;
|
||||
if (buf[i - 1] == '\r')
|
||||
buf[--i] = '\0';
|
||||
if (i == 0)
|
||||
goto err;
|
||||
again = (buf[i - 1] == '\\');
|
||||
|
||||
for (j = 0; j < i; j++) {
|
||||
if (!ossl_isxdigit(buf[j])) {
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[i] = '\0';
|
||||
/*
|
||||
* We have now cleared all the crap off the end of the line
|
||||
*/
|
||||
if (i < 2)
|
||||
goto err;
|
||||
|
||||
bufp = (unsigned char *)buf;
|
||||
if (first) {
|
||||
first = 0;
|
||||
if ((bufp[0] == '0') && (bufp[1] == '0')) {
|
||||
bufp += 2;
|
||||
i -= 2;
|
||||
}
|
||||
}
|
||||
k = 0;
|
||||
i -= again;
|
||||
if (i % 2 != 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_ODD_NUMBER_OF_CHARS);
|
||||
OPENSSL_free(s);
|
||||
return 0;
|
||||
}
|
||||
i /= 2;
|
||||
if (num + i > slen) {
|
||||
sp = OPENSSL_clear_realloc(s, slen, num + i * 2);
|
||||
if (sp == NULL) {
|
||||
OPENSSL_free(s);
|
||||
return 0;
|
||||
}
|
||||
s = sp;
|
||||
slen = num + i * 2;
|
||||
}
|
||||
for (j = 0; j < i; j++, k += 2) {
|
||||
for (n = 0; n < 2; n++) {
|
||||
m = OPENSSL_hexchar2int(bufp[k + n]);
|
||||
if (m < 0) {
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_NON_HEX_CHARACTERS);
|
||||
goto err;
|
||||
}
|
||||
s[num + j] <<= 4;
|
||||
s[num + j] |= m;
|
||||
}
|
||||
}
|
||||
num += i;
|
||||
if (again)
|
||||
bufsize = BIO_gets(bp, buf, size);
|
||||
else
|
||||
break;
|
||||
}
|
||||
bs->length = num;
|
||||
bs->data = s;
|
||||
return 1;
|
||||
err:
|
||||
ERR_raise(ERR_LIB_ASN1, ASN1_R_SHORT_LINE);
|
||||
OPENSSL_free(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2a_ASN1_ENUMERATED(BIO *bp, const ASN1_ENUMERATED *a)
|
||||
{
|
||||
return i2a_ASN1_INTEGER(bp, a);
|
||||
}
|
||||
|
||||
int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size)
|
||||
{
|
||||
int rv = a2i_ASN1_INTEGER(bp, bs, buf, size);
|
||||
if (rv == 1)
|
||||
bs->type = V_ASN1_INTEGER | (bs->type & V_ASN1_NEG);
|
||||
return rv;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user