mirror of
https://github.com/Mbed-TLS/mbedtls.git
synced 2025-02-23 03:39:53 +00:00
1420 lines
43 KiB
Perl
Executable File
1420 lines
43 KiB
Perl
Executable File
#!/usr/bin/env perl
|
|
#
|
|
# This is a proof-of-concept script to show that the client and server wrappers
|
|
# can be created by a script. It is not hooked into the build, so is run
|
|
# manually and the output files are what are to be reviewed. In due course
|
|
# this will be replaced by a Python script.
|
|
#
|
|
# Copyright The Mbed TLS Contributors
|
|
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
#
|
|
use strict;
|
|
use Data::Dumper;
|
|
use JSON qw(encode_json);
|
|
|
|
my $debug = 0;
|
|
|
|
# Globals (sorry!)
|
|
my %functions = get_functions();
|
|
my @functions = sort keys %functions;
|
|
|
|
# get_functions(), called above, returns a data structure for each function
|
|
# that we need to create client and server stubs for. In this example Perl script,
|
|
# the function declarations we want are in the data section (after __END__ at
|
|
# the bottom of this file), but a production Python version should process
|
|
# psa_crypto.h.
|
|
#
|
|
# In this script, the data for psa_crypto_init() looks like:
|
|
#
|
|
# "psa_crypto_init": {
|
|
# "return": { # Info on return type
|
|
# "type": "psa_status_t", # Return type
|
|
# "name": "status", # Name to be used for this in C code
|
|
# "default": "PSA_ERROR_CORRUPTION_DETECTED" # Default value
|
|
# },
|
|
# "args": [], # void function, so args empty
|
|
# }
|
|
#
|
|
# The data for psa_hash_compute() looks like:
|
|
#
|
|
# "psa_hash_compute": {
|
|
# "return": { # Information on return type
|
|
# "type": "psa_status_t",
|
|
# "name": "status",
|
|
# "default": "PSA_ERROR_CORRUPTION_DETECTED"
|
|
# },
|
|
# "args": [{
|
|
# "type": "psa_algorithm_t", # Type of first argument
|
|
# "ctypename": "psa_algorithm_t ", # C type with trailing spaces
|
|
# # (so that e.g. `char *` looks ok)
|
|
# "name": "alg",
|
|
# "is_output": 0
|
|
# }, {
|
|
# "type": "const buffer", # Specially created
|
|
# "ctypename": "", # (so no C type)
|
|
# "name": "input, input_length", # A pair of arguments
|
|
# "is_output": 0 # const, so not an output argument
|
|
# }, {
|
|
# "type": "buffer", # Specially created
|
|
# "ctypename": "",
|
|
# "name": "hash, hash_size",
|
|
# "is_output": 1 # Not const, so output argument
|
|
# }, {
|
|
# "type": "size_t", # size_t *hash_length
|
|
# "ctypename": "size_t ",
|
|
# "name": "*hash_length", # * comes into the name
|
|
# "is_output": 1
|
|
# }
|
|
# ],
|
|
# },
|
|
#
|
|
# It's possible that a production version might not need both type and ctypename;
|
|
# that was done for convenience and future-proofing during development.
|
|
|
|
# We'll do psa_crypto_init() first
|
|
put_crypto_init_first(\@functions);
|
|
|
|
write_function_codes("psa_functions_codes.h");
|
|
|
|
write_client_calls("psa_sim_crypto_client.c");
|
|
|
|
write_server_implementations("psa_sim_crypto_server.c");
|
|
|
|
sub write_function_codes
|
|
{
|
|
my ($file) = @_;
|
|
|
|
open(my $fh, ">", $file) || die("$0: $file: $!\n");
|
|
|
|
# NOTE: psa_crypto_init() is written manually
|
|
|
|
print $fh <<EOF;
|
|
/* THIS FILE WAS AUTO-GENERATED BY psa_sim_generate.pl. DO NOT EDIT!! */
|
|
|
|
/*
|
|
* Copyright The Mbed TLS Contributors
|
|
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
*/
|
|
|
|
#ifndef _PSA_FUNCTIONS_CODES_H_
|
|
#define _PSA_FUNCTIONS_CODES_H_
|
|
|
|
enum {
|
|
/* Start here to avoid overlap with PSA_IPC_CONNECT, PSA_IPC_DISCONNECT
|
|
* and VERSION_REQUEST */
|
|
PSA_CRYPTO_INIT = 100,
|
|
EOF
|
|
|
|
for my $function (@functions) {
|
|
my $enum = uc($function);
|
|
if ($enum ne "PSA_CRYPTO_INIT") {
|
|
print $fh <<EOF;
|
|
$enum,
|
|
EOF
|
|
}
|
|
}
|
|
|
|
print $fh <<EOF;
|
|
};
|
|
|
|
#endif /* _PSA_FUNCTIONS_CODES_H_ */
|
|
EOF
|
|
|
|
close($fh);
|
|
}
|
|
|
|
sub write_client_calls
|
|
{
|
|
my ($file) = @_;
|
|
|
|
open(my $fh, ">", $file) || die("$0: $file: $!\n");
|
|
|
|
print $fh client_calls_header();
|
|
|
|
for my $function (@functions) {
|
|
# psa_crypto_init() is hand written to establish connection to server
|
|
if ($function ne "psa_crypto_init") {
|
|
my $f = $functions{$function};
|
|
output_client($fh, $f, $function);
|
|
}
|
|
}
|
|
|
|
close($fh);
|
|
}
|
|
|
|
sub write_server_implementations
|
|
{
|
|
my ($file) = @_;
|
|
|
|
open(my $fh, ">", $file) || die("$0: $file: $!\n");
|
|
|
|
print $fh server_implementations_header();
|
|
|
|
print $fh debug_functions() if $debug;
|
|
|
|
for my $function (@functions) {
|
|
my $f = $functions{$function};
|
|
output_server_wrapper($fh, $f, $function);
|
|
}
|
|
|
|
# Now output a switch statement that calls each of the wrappers
|
|
|
|
print $fh <<EOF;
|
|
|
|
psa_status_t psa_crypto_call(psa_msg_t msg)
|
|
{
|
|
int ok = 0;
|
|
|
|
int func = msg.type;
|
|
|
|
/* We only expect a single input buffer, with everything serialised in it */
|
|
if (msg.in_size[1] != 0 || msg.in_size[2] != 0 || msg.in_size[3] != 0) {
|
|
return PSA_ERROR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
/* We expect exactly 2 output buffers, one for size, the other for data */
|
|
if (msg.out_size[0] != sizeof(size_t) || msg.out_size[1] == 0 ||
|
|
msg.out_size[2] != 0 || msg.out_size[3] != 0) {
|
|
return PSA_ERROR_INVALID_ARGUMENT;
|
|
}
|
|
|
|
uint8_t *in_params = NULL;
|
|
size_t in_params_len = 0;
|
|
uint8_t *out_params = NULL;
|
|
size_t out_params_len = 0;
|
|
|
|
in_params_len = msg.in_size[0];
|
|
in_params = malloc(in_params_len);
|
|
if (in_params == NULL) {
|
|
return PSA_ERROR_INSUFFICIENT_MEMORY;
|
|
}
|
|
|
|
/* Read the bytes from the client */
|
|
size_t actual = psa_read(msg.handle, 0, in_params, in_params_len);
|
|
if (actual != in_params_len) {
|
|
free(in_params);
|
|
return PSA_ERROR_CORRUPTION_DETECTED;
|
|
}
|
|
|
|
switch (func) {
|
|
EOF
|
|
|
|
for my $function (@functions) {
|
|
my $f = $functions{$function};
|
|
my $enum = uc($function);
|
|
|
|
# Create this call, in a way acceptable to uncustify:
|
|
# ok = ${function}_wrapper(in_params, in_params_len,
|
|
# &out_params, &out_params_len);
|
|
my $first_line = " ok = ${function}_wrapper(in_params, in_params_len,";
|
|
my $idx = index($first_line, "(");
|
|
die("can't find (") if $idx < 0;
|
|
my $indent = " " x ($idx + 1);
|
|
|
|
print $fh <<EOF;
|
|
case $enum:
|
|
$first_line
|
|
$indent&out_params, &out_params_len);
|
|
break;
|
|
EOF
|
|
}
|
|
|
|
print $fh <<EOF;
|
|
}
|
|
|
|
free(in_params);
|
|
|
|
if (out_params_len > msg.out_size[1]) {
|
|
fprintf(stderr, "unable to write %zu bytes into buffer of %zu bytes\\n",
|
|
out_params_len, msg.out_size[1]);
|
|
exit(1);
|
|
}
|
|
|
|
/* Write the exact amount of data we're returning */
|
|
psa_write(msg.handle, 0, &out_params_len, sizeof(out_params_len));
|
|
|
|
/* And write the data itself */
|
|
if (out_params_len) {
|
|
psa_write(msg.handle, 1, out_params, out_params_len);
|
|
}
|
|
|
|
free(out_params);
|
|
|
|
return ok ? PSA_SUCCESS : PSA_ERROR_GENERIC_ERROR;
|
|
}
|
|
EOF
|
|
|
|
close($fh);
|
|
}
|
|
|
|
sub server_implementations_header
|
|
{
|
|
return <<'EOF';
|
|
/* THIS FILE WAS AUTO-GENERATED BY psa_sim_generate.pl. DO NOT EDIT!! */
|
|
|
|
/* server implementations */
|
|
|
|
/*
|
|
* Copyright The Mbed TLS Contributors
|
|
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <psa/crypto.h>
|
|
|
|
#include "psa_functions_codes.h"
|
|
#include "psa_sim_serialise.h"
|
|
|
|
#include "service.h"
|
|
EOF
|
|
}
|
|
|
|
sub client_calls_header
|
|
{
|
|
my $code = <<'EOF';
|
|
/* THIS FILE WAS AUTO-GENERATED BY psa_sim_generate.pl. DO NOT EDIT!! */
|
|
|
|
/* client calls */
|
|
|
|
/*
|
|
* Copyright The Mbed TLS Contributors
|
|
* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
/* Includes from psasim */
|
|
#include <client.h>
|
|
#include <util.h>
|
|
#include "psa_manifest/sid.h"
|
|
#include "psa_functions_codes.h"
|
|
#include "psa_sim_serialise.h"
|
|
|
|
/* Includes from mbedtls */
|
|
#include "mbedtls/version.h"
|
|
#include "psa/crypto.h"
|
|
|
|
#define CLIENT_PRINT(fmt, ...) \
|
|
PRINT("Client: " fmt, ##__VA_ARGS__)
|
|
|
|
static psa_handle_t handle = -1;
|
|
EOF
|
|
|
|
$code .= debug_functions() if $debug;
|
|
|
|
$code .= <<'EOF';
|
|
|
|
int psa_crypto_call(int function,
|
|
uint8_t *in_params, size_t in_params_len,
|
|
uint8_t **out_params, size_t *out_params_len)
|
|
{
|
|
// psa_outvec outvecs[1];
|
|
if (handle < 0) {
|
|
fprintf(stderr, "NOT CONNECTED\n");
|
|
exit(1);
|
|
}
|
|
|
|
psa_invec invec;
|
|
invec.base = in_params;
|
|
invec.len = in_params_len;
|
|
|
|
size_t max_receive = 8192;
|
|
uint8_t *receive = malloc(max_receive);
|
|
if (receive == NULL) {
|
|
fprintf(stderr, "FAILED to allocate %u bytes\n", (unsigned) max_receive);
|
|
exit(1);
|
|
}
|
|
|
|
size_t actual_received = 0;
|
|
|
|
psa_outvec outvecs[2];
|
|
outvecs[0].base = &actual_received;
|
|
outvecs[0].len = sizeof(actual_received);
|
|
outvecs[1].base = receive;
|
|
outvecs[1].len = max_receive;
|
|
|
|
psa_status_t status = psa_call(handle, function, &invec, 1, outvecs, 2);
|
|
if (status != PSA_SUCCESS) {
|
|
free(receive);
|
|
return 0;
|
|
}
|
|
|
|
*out_params = receive;
|
|
*out_params_len = actual_received;
|
|
|
|
return 1; // success
|
|
}
|
|
|
|
psa_status_t psa_crypto_init(void)
|
|
{
|
|
char mbedtls_version[18];
|
|
uint8_t *result = NULL;
|
|
size_t result_length;
|
|
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
|
|
|
|
mbedtls_version_get_string_full(mbedtls_version);
|
|
CLIENT_PRINT("%s", mbedtls_version);
|
|
|
|
CLIENT_PRINT("My PID: %d", getpid());
|
|
|
|
CLIENT_PRINT("PSA version: %u", psa_version(PSA_SID_CRYPTO_SID));
|
|
handle = psa_connect(PSA_SID_CRYPTO_SID, 1);
|
|
|
|
if (handle < 0) {
|
|
CLIENT_PRINT("Couldn't connect %d", handle);
|
|
return PSA_ERROR_COMMUNICATION_FAILURE;
|
|
}
|
|
|
|
int ok = psa_crypto_call(PSA_CRYPTO_INIT, NULL, 0, &result, &result_length);
|
|
CLIENT_PRINT("PSA_CRYPTO_INIT returned: %d", ok);
|
|
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
|
|
uint8_t *rpos = result;
|
|
size_t rremain = result_length;
|
|
|
|
ok = psasim_deserialise_begin(&rpos, &rremain);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
|
|
ok = psasim_deserialise_psa_status_t(&rpos, &rremain, &status);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
|
|
fail:
|
|
free(result);
|
|
|
|
return status;
|
|
}
|
|
|
|
void mbedtls_psa_crypto_free(void)
|
|
{
|
|
CLIENT_PRINT("Closing handle");
|
|
psa_close(handle);
|
|
handle = -1;
|
|
}
|
|
EOF
|
|
}
|
|
|
|
sub debug_functions
|
|
{
|
|
return <<EOF;
|
|
|
|
static inline char hex_digit(char nibble) {
|
|
return (nibble < 10) ? (nibble + '0') : (nibble + 'a' - 10);
|
|
}
|
|
|
|
int hex_byte(char *p, uint8_t b)
|
|
{
|
|
p[0] = hex_digit(b >> 4);
|
|
p[1] = hex_digit(b & 0x0F);
|
|
|
|
return 2;
|
|
}
|
|
|
|
int hex_uint16(char *p, uint16_t b)
|
|
{
|
|
hex_byte(p, b >> 8);
|
|
hex_byte(p + 2, b & 0xFF);
|
|
|
|
return 4;
|
|
}
|
|
|
|
char human_char(uint8_t c)
|
|
{
|
|
return (c >= ' ' && c <= '~') ? (char)c : '.';
|
|
}
|
|
|
|
void dump_buffer(const uint8_t *buffer, size_t len)
|
|
{
|
|
char line[80];
|
|
|
|
const uint8_t *p = buffer;
|
|
|
|
size_t max = (len > 0xFFFF) ? 0xFFFF : len;
|
|
|
|
for (size_t i = 0; i < max; i += 16) {
|
|
|
|
char *q = line;
|
|
|
|
q += hex_uint16(q, (uint16_t)i);
|
|
*q++ = ' ';
|
|
*q++ = ' ';
|
|
|
|
size_t ll = (i + 16 > max) ? (max % 16) : 16;
|
|
|
|
size_t j;
|
|
for (j = 0; j < ll; j++) {
|
|
q += hex_byte(q, p[i + j]);
|
|
*q++ = ' ';
|
|
}
|
|
|
|
while (j++ < 16) {
|
|
*q++ = ' ';
|
|
*q++ = ' ';
|
|
*q++ = ' ';
|
|
}
|
|
|
|
*q++ = ' ';
|
|
|
|
for (j = 0; j < ll; j++) {
|
|
*q++ = human_char(p[i + j]);
|
|
}
|
|
|
|
*q = '\\0';
|
|
|
|
printf("%s\\n", line);
|
|
}
|
|
}
|
|
|
|
void hex_dump(uint8_t *p, size_t n)
|
|
{
|
|
for (size_t i = 0; i < n; i++) {
|
|
printf("0x%02X ", p[i]);
|
|
}
|
|
printf("\\n");
|
|
}
|
|
EOF
|
|
}
|
|
|
|
sub output_server_wrapper
|
|
{
|
|
my ($fh, $f, $name) = @_;
|
|
|
|
my $ret_type = $f->{return}->{type};
|
|
my $ret_name = $f->{return}->{name};
|
|
my $ret_default = $f->{return}->{default};
|
|
|
|
my @buffers = (); # We need to free() these on exit
|
|
|
|
print $fh <<EOF;
|
|
|
|
// Returns 1 for success, 0 for failure
|
|
int ${name}_wrapper(
|
|
uint8_t *in_params, size_t in_params_len,
|
|
uint8_t **out_params, size_t *out_params_len)
|
|
{
|
|
$ret_type $ret_name = $ret_default;
|
|
EOF
|
|
# Output the variables we will need when we call the target function
|
|
|
|
my $args = $f->{args};
|
|
|
|
for my $i (0 .. $#$args) {
|
|
my $arg = $args->[$i];
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $argname = $arg->{name};
|
|
$argtype =~ s/^const //;
|
|
|
|
if ($argtype =~ /^(const )?buffer$/) {
|
|
my ($n1, $n2) = split(/,\s*/, $argname);
|
|
print $fh <<EOF;
|
|
uint8_t *$n1 = NULL;
|
|
size_t $n2;
|
|
EOF
|
|
push(@buffers, $n1); # Add to the list to be free()d at end
|
|
} else {
|
|
$argname =~ s/^\*//; # Remove any leading *
|
|
my $pointer = ($argtype =~ /^psa_\w+_operation_t/) ? "*" : "";
|
|
print $fh <<EOF;
|
|
$argtype $pointer$argname;
|
|
EOF
|
|
}
|
|
}
|
|
|
|
print $fh "\n";
|
|
|
|
if ($#$args >= 0) { # If we have any args (>= 0)
|
|
print $fh <<EOF;
|
|
uint8_t *pos = in_params;
|
|
size_t remaining = in_params_len;
|
|
EOF
|
|
}
|
|
|
|
print $fh <<EOF;
|
|
uint8_t *result = NULL;
|
|
int ok;
|
|
EOF
|
|
|
|
print $fh <<EOF if $debug;
|
|
|
|
printf("$name: server\\n");
|
|
EOF
|
|
if ($#$args >= 0) { # If we have any args (>= 0)
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_deserialise_begin(&pos, &remaining);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
}
|
|
|
|
for my $i (0 .. $#$args) {
|
|
my $arg = $args->[$i];
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $argname = $arg->{name};
|
|
my $sep = ($i == $#$args) ? ";" : " +";
|
|
$argtype =~ s/^const //;
|
|
|
|
if ($argtype =~ /^(const )?buffer$/) {
|
|
my ($n1, $n2) = split(/,\s*/, $argname);
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_deserialise_${argtype}(&pos, &remaining, &$n1, &$n2);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
} else {
|
|
$argname =~ s/^\*//; # Remove any leading *
|
|
my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_${server_specific}deserialise_${argtype}(&pos, &remaining, &$argname);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
}
|
|
}
|
|
|
|
print $fh <<EOF;
|
|
|
|
// Now we call the actual target function
|
|
EOF
|
|
output_call($fh, $f, $name, 1);
|
|
|
|
my @outputs = grep($_->{is_output}, @$args);
|
|
|
|
my $sep1 = ($ret_type eq "void") ? ";" : " +";
|
|
|
|
print $fh <<EOF;
|
|
|
|
// NOTE: Should really check there is no overflow as we go along.
|
|
size_t result_size =
|
|
psasim_serialise_begin_needs()$sep1
|
|
EOF
|
|
|
|
if ($ret_type ne "void") {
|
|
my $sep = ($#outputs < 0) ? ";" : " +";
|
|
print $fh <<EOF;
|
|
psasim_serialise_${ret_type}_needs($ret_name)$sep
|
|
EOF
|
|
}
|
|
|
|
for my $i (0 .. $#outputs) {
|
|
my $arg = $outputs[$i];
|
|
die("$i: this should have been filtered out by grep") unless $arg->{is_output};
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $argname = $arg->{name};
|
|
my $sep = ($i == $#outputs) ? ";" : " +";
|
|
$argtype =~ s/^const //;
|
|
$argname =~ s/^\*//; # Remove any leading *
|
|
my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
|
|
|
|
print $fh <<EOF;
|
|
psasim_${server_specific}serialise_${argtype}_needs($argname)$sep
|
|
EOF
|
|
}
|
|
|
|
print $fh <<EOF;
|
|
|
|
result = malloc(result_size);
|
|
if (result == NULL) {
|
|
goto fail;
|
|
}
|
|
|
|
uint8_t *rpos = result;
|
|
size_t rremain = result_size;
|
|
|
|
ok = psasim_serialise_begin(&rpos, &rremain);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
|
|
if ($ret_type ne "void") {
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_serialise_${ret_type}(&rpos, &rremain, $ret_name);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
}
|
|
|
|
my @outputs = grep($_->{is_output}, @$args);
|
|
|
|
for my $i (0 .. $#outputs) {
|
|
my $arg = $outputs[$i];
|
|
die("$i: this should have been filtered out by grep") unless $arg->{is_output};
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $argname = $arg->{name};
|
|
my $sep = ($i == $#outputs) ? ";" : " +";
|
|
$argtype =~ s/^const //;
|
|
|
|
if ($argtype eq "buffer") {
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_serialise_buffer(&rpos, &rremain, $argname);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
} else {
|
|
if ($argname =~ /^\*/) {
|
|
$argname =~ s/^\*//; # since it's already a pointer
|
|
} else {
|
|
die("$0: $argname: HOW TO OUTPUT?\n");
|
|
}
|
|
|
|
my $server_specific = ($argtype =~ /^psa_\w+_operation_t/) ? "server_" : "";
|
|
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_${server_specific}serialise_${argtype}(&rpos, &rremain, $argname);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
}
|
|
}
|
|
|
|
my $free_buffers = join("", map { " free($_);\n" } @buffers);
|
|
$free_buffers = "\n" . $free_buffers if length($free_buffers);
|
|
|
|
print $fh <<EOF;
|
|
|
|
*out_params = result;
|
|
*out_params_len = result_size;
|
|
$free_buffers
|
|
return 1; // success
|
|
|
|
fail:
|
|
free(result);
|
|
$free_buffers
|
|
return 0; // This shouldn't happen!
|
|
}
|
|
EOF
|
|
}
|
|
|
|
sub output_client
|
|
{
|
|
my ($fh, $f, $name) = @_;
|
|
|
|
print $fh "\n";
|
|
|
|
output_definition_begin($fh, $f, $name);
|
|
|
|
my $ret_type = $f->{return}->{type};
|
|
my $ret_name = $f->{return}->{name};
|
|
my $ret_default = $f->{return}->{default};
|
|
|
|
print $fh <<EOF;
|
|
{
|
|
uint8_t *params = NULL;
|
|
uint8_t *result = NULL;
|
|
size_t result_length;
|
|
$ret_type $ret_name = $ret_default;
|
|
EOF
|
|
|
|
print $fh <<EOF if $debug;
|
|
|
|
printf("$name: client\\n");
|
|
EOF
|
|
|
|
print $fh <<EOF;
|
|
|
|
size_t needed = psasim_serialise_begin_needs() +
|
|
EOF
|
|
|
|
my $args = $f->{args};
|
|
|
|
for my $i (0 .. $#$args) {
|
|
my $arg = $args->[$i];
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $argname = $arg->{name};
|
|
my $sep = ($i == $#$args) ? ";" : " +";
|
|
$argtype =~ s/^const //;
|
|
|
|
print $fh <<EOF;
|
|
psasim_serialise_${argtype}_needs($argname)$sep
|
|
EOF
|
|
}
|
|
|
|
print $fh <<EOF;
|
|
|
|
params = malloc(needed);
|
|
if (params == NULL) {
|
|
status = PSA_ERROR_INSUFFICIENT_MEMORY;
|
|
goto fail;
|
|
}
|
|
|
|
uint8_t *pos = params;
|
|
size_t remaining = needed;
|
|
int ok;
|
|
ok = psasim_serialise_begin(&pos, &remaining);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
|
|
for my $i (0 .. $#$args) {
|
|
my $arg = $args->[$i];
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $argname = $arg->{name};
|
|
my $sep = ($i == $#$args) ? ";" : " +";
|
|
$argtype =~ s/^const //;
|
|
|
|
print $fh <<EOF;
|
|
ok = psasim_serialise_${argtype}(&pos, &remaining, $argname);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
}
|
|
|
|
print $fh <<EOF if $debug;
|
|
|
|
printf("client sending %d:\\n", (int)(pos - params));
|
|
dump_buffer(params, (size_t)(pos - params));
|
|
EOF
|
|
|
|
my $enum = uc($name);
|
|
|
|
print $fh <<EOF;
|
|
|
|
ok = psa_crypto_call($enum,
|
|
params, (size_t) (pos - params), &result, &result_length);
|
|
if (!ok) {
|
|
printf("XXX server call failed\\n");
|
|
goto fail;
|
|
}
|
|
EOF
|
|
|
|
print $fh <<EOF if $debug;
|
|
|
|
printf("client receiving %d:\\n", (int)result_length);
|
|
dump_buffer(result, result_length);
|
|
EOF
|
|
|
|
print $fh <<EOF;
|
|
|
|
uint8_t *rpos = result;
|
|
size_t rremain = result_length;
|
|
|
|
ok = psasim_deserialise_begin(&rpos, &rremain);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_deserialise_$ret_type(&rpos, &rremain, &$ret_name);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
|
|
my @outputs = grep($_->{is_output}, @$args);
|
|
|
|
for my $i (0 .. $#outputs) {
|
|
my $arg = $outputs[$i];
|
|
die("$i: this should have been filtered out by grep") unless $arg->{is_output};
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $argname = $arg->{name};
|
|
my $sep = ($i == $#outputs) ? ";" : " +";
|
|
$argtype =~ s/^const //;
|
|
|
|
if ($argtype eq "buffer") {
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_deserialise_return_buffer(&rpos, &rremain, $argname);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
} else {
|
|
if ($argname =~ /^\*/) {
|
|
$argname =~ s/^\*//; # since it's already a pointer
|
|
} else {
|
|
die("$0: $argname: HOW TO OUTPUT?\n");
|
|
}
|
|
|
|
print $fh <<EOF;
|
|
|
|
ok = psasim_deserialise_${argtype}(&rpos, &rremain, $argname);
|
|
if (!ok) {
|
|
goto fail;
|
|
}
|
|
EOF
|
|
}
|
|
}
|
|
print $fh <<EOF;
|
|
|
|
fail:
|
|
free(params);
|
|
free(result);
|
|
|
|
return $ret_name;
|
|
}
|
|
EOF
|
|
}
|
|
|
|
sub output_declaration
|
|
{
|
|
my ($f, $name) = @_;
|
|
|
|
output_signature($f, $name, "declaration");
|
|
}
|
|
|
|
sub output_definition_begin
|
|
{
|
|
my ($fh, $f, $name) = @_;
|
|
|
|
output_signature($fh, $f, $name, "definition");
|
|
}
|
|
|
|
sub output_call
|
|
{
|
|
my ($fh, $f, $name, $is_server) = @_;
|
|
|
|
my $ret_name = $f->{return}->{name};
|
|
my $args = $f->{args};
|
|
|
|
print $fh "\n $ret_name = $name(\n";
|
|
|
|
print $fh " );\n" if $#$args < 0; # If no arguments, empty arg list
|
|
|
|
for my $i (0 .. $#$args) {
|
|
my $arg = $args->[$i];
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $argname = $arg->{name};
|
|
|
|
if ($argtype =~ /^(const )?buffer$/) {
|
|
my ($n1, $n2) = split(/,\s*/, $argname);
|
|
print $fh " $n1, $n2";
|
|
} else {
|
|
$argname =~ s/^\*/\&/; # Replace leading * with &
|
|
if ($is_server && $argtype =~ /^psa_\w+_operation_t/) {
|
|
$argname =~ s/^\&//; # Actually, for psa_XXX_operation_t, don't do this on the server side
|
|
}
|
|
print $fh " $argname";
|
|
}
|
|
my $sep = ($i == $#$args) ? "\n );" : ",";
|
|
print $fh "$sep\n";
|
|
}
|
|
}
|
|
|
|
sub output_signature
|
|
{
|
|
my ($fh, $f, $name, $what) = @_;
|
|
|
|
my $ret_type = $f->{return}->{type};
|
|
my $args = $f->{args};
|
|
|
|
my $final_sep = ($what eq "declaration") ? "\n);" : "\n )";
|
|
|
|
print $fh "\n$ret_type $name(\n";
|
|
|
|
print $fh " void\n)\n" if $#$args < 0; # No arguments
|
|
|
|
for my $i (0 .. $#$args) {
|
|
my $arg = $args->[$i];
|
|
my $argtype = $arg->{type}; # e.g. int, psa_algorithm_t, or "buffer"
|
|
my $ctypename = $arg->{ctypename}; # e.g. "int ", "char *"; empty for buffer
|
|
my $argname = $arg->{name};
|
|
|
|
if ($argtype =~ /^(const )?buffer$/) {
|
|
my $const = length($1) ? "const " : "";
|
|
my ($n1, $n2) = split(/,/, $argname);
|
|
print $fh " ${const}uint8_t *$n1, size_t $n2";
|
|
} else {
|
|
print $fh " $ctypename$argname";
|
|
}
|
|
my $sep = ($i == $#$args) ? $final_sep : ",";
|
|
print $fh "$sep\n";
|
|
}
|
|
}
|
|
|
|
sub get_functions
|
|
{
|
|
my $src = "";
|
|
while (<DATA>) {
|
|
chomp;
|
|
s/\/\/.*//;
|
|
s/\s+^//;
|
|
s/\s+/ /g;
|
|
$_ .= "\n";
|
|
$src .= $_;
|
|
}
|
|
|
|
$src =~ s/\/\*.*?\*\///gs;
|
|
|
|
my @src = split(/\n+/, $src);
|
|
|
|
my @rebuild = ();
|
|
my %funcs = ();
|
|
for (my $i = 0; $i <= $#src; $i++) {
|
|
my $line = $src[$i];
|
|
if ($line =~ /^psa_status_t (psa_\w*)\(/) { # begin function definition
|
|
#print "have one $line\n";
|
|
while ($line !~ /;/) {
|
|
$line .= $src[$i + 1];
|
|
$i++;
|
|
}
|
|
$line =~ s/\s+/ /g;
|
|
if ($line =~ /(\w+)\s+\b(\w+)\s*\(\s*(.*\S)\s*\)\s*[;{]/s) {
|
|
my ($ret_type, $func, $args) = ($1, $2, $3);
|
|
my $copy = $line;
|
|
$copy =~ s/{$//;
|
|
my $f = {
|
|
"orig" => $copy,
|
|
};
|
|
|
|
my @args = split(/\s*,\s*/, $args);
|
|
|
|
my $ret_name = "";
|
|
$ret_name = "status" if $ret_type eq "psa_status_t";
|
|
die("ret_name for $ret_type?") unless length($ret_name);
|
|
my $ret_default = "";
|
|
$ret_default = "PSA_ERROR_CORRUPTION_DETECTED" if $ret_type eq "psa_status_t";
|
|
die("ret_default for $ret_type?") unless length($ret_default);
|
|
|
|
#print "FUNC $func RET_NAME $ret_name RET_TYPE $ret_type ARGS (", join("; ", @args), ")\n";
|
|
|
|
$f->{return} = {
|
|
"type" => $ret_type,
|
|
"default" => $ret_default,
|
|
"name" => $ret_name,
|
|
};
|
|
$f->{args} = [];
|
|
# psa_algorithm_t alg; const uint8_t *input; size_t input_length; uint8_t *hash; size_t hash_size; size_t *hash_length
|
|
for (my $i = 0; $i <= $#args; $i++) {
|
|
my $arg = $args[$i];
|
|
# "type" => "psa_algorithm_t",
|
|
# "ctypename" => "psa_algorithm_t ",
|
|
# "name" => "alg",
|
|
# "is_output" => 0,
|
|
my ($type, $ctype, $name, $is_output);
|
|
if ($arg =~ /^(\w+)\s+(\w+)$/) { # e.g. psa_algorithm_t alg
|
|
($type, $name) = ($1, $2);
|
|
$ctype = $type . " ";
|
|
$is_output = 0;
|
|
} elsif ($arg =~ /^((const)\s+)?uint8_t\s*\*\s*(\w+)$/) {
|
|
$type = "buffer";
|
|
$is_output = (length($1) == 0) ? 1 : 0;
|
|
$type = "const buffer" if !$is_output;
|
|
$ctype = "";
|
|
$name = $3;
|
|
#print("$arg: $name: might be a buffer?\n");
|
|
die("$arg: not a buffer 1!\n") if $i == $#args;
|
|
my $next = $args[$i + 1];
|
|
die("$arg: not a buffer 2!\n") if $next !~ /^size_t\s+(${name}_\w+)$/;
|
|
$i++; # We're using the next param here
|
|
my $nname = $1;
|
|
$name .= ", " . $nname;
|
|
} elsif ($arg =~ /^((const)\s+)?(\w+)\s*\*(\w+)$/) {
|
|
($type, $name) = ($3, "*" . $4);
|
|
$ctype = $1 . $type . " ";
|
|
$is_output = (length($1) == 0) ? 1 : 0;
|
|
} elsif ($arg eq "void") {
|
|
# we'll just ignore this one
|
|
} else {
|
|
die("ARG HELP $arg\n");
|
|
}
|
|
#print "$arg => <$type><$ctype><$name><$is_output>\n";
|
|
if ($arg ne "void") {
|
|
push(@{$f->{args}}, {
|
|
"type" => $type,
|
|
"ctypename" => $ctype,
|
|
"name" => $name,
|
|
"is_output" => $is_output,
|
|
});
|
|
}
|
|
}
|
|
$funcs{$func} = $f;
|
|
} else {
|
|
die("FAILED");
|
|
}
|
|
push(@rebuild, $line);
|
|
} elsif ($line =~ /^static psa_\w+_t (psa_\w*)\(/) { # begin function definition
|
|
# IGNORE static functions
|
|
} else {
|
|
if ($line =~ /psa_/) {
|
|
print "NOT PARSED: $line\n";
|
|
}
|
|
push(@rebuild, $line);
|
|
}
|
|
}
|
|
|
|
#print ::Dumper(\%funcs);
|
|
#exit;
|
|
|
|
return %funcs;
|
|
}
|
|
|
|
sub put_crypto_init_first
|
|
{
|
|
my ($functions) = @_;
|
|
|
|
my $want_first = "psa_crypto_init";
|
|
|
|
my $idx = undef;
|
|
for my $i (0 .. $#$functions) {
|
|
if ($functions->[$i] eq $want_first) {
|
|
$idx = $i;
|
|
last;
|
|
}
|
|
}
|
|
|
|
if (defined($idx) && $idx != 0) { # Do nothing if already first
|
|
splice(@$functions, $idx, 1);
|
|
unshift(@$functions, $want_first);
|
|
}
|
|
}
|
|
|
|
__END__
|
|
/**
|
|
* \brief Library initialization.
|
|
*
|
|
* Applications must call this function before calling any other
|
|
* function in this module.
|
|
*
|
|
* Applications may call this function more than once. Once a call
|
|
* succeeds, subsequent calls are guaranteed to succeed.
|
|
*
|
|
* If the application calls other functions before calling psa_crypto_init(),
|
|
* the behavior is undefined. Implementations are encouraged to either perform
|
|
* the operation as if the library had been initialized or to return
|
|
* #PSA_ERROR_BAD_STATE or some other applicable error. In particular,
|
|
* implementations should not return a success status if the lack of
|
|
* initialization may have security implications, for example due to improper
|
|
* seeding of the random number generator.
|
|
*
|
|
* \retval #PSA_SUCCESS \emptydescription
|
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
|
|
* \retval #PSA_ERROR_INSUFFICIENT_STORAGE \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_INSUFFICIENT_ENTROPY \emptydescription
|
|
* \retval #PSA_ERROR_STORAGE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_DATA_INVALID \emptydescription
|
|
* \retval #PSA_ERROR_DATA_CORRUPT \emptydescription
|
|
*/
|
|
psa_status_t psa_crypto_init(void);
|
|
|
|
/** Calculate the hash (digest) of a message.
|
|
*
|
|
* \note To verify the hash of a message against an
|
|
* expected value, use psa_hash_compare() instead.
|
|
*
|
|
* \param alg The hash algorithm to compute (\c PSA_ALG_XXX value
|
|
* such that #PSA_ALG_IS_HASH(\p alg) is true).
|
|
* \param[in] input Buffer containing the message to hash.
|
|
* \param input_length Size of the \p input buffer in bytes.
|
|
* \param[out] hash Buffer where the hash is to be written.
|
|
* \param hash_size Size of the \p hash buffer in bytes.
|
|
* \param[out] hash_length On success, the number of bytes
|
|
* that make up the hash value. This is always
|
|
* #PSA_HASH_LENGTH(\p alg).
|
|
*
|
|
* \retval #PSA_SUCCESS
|
|
* Success.
|
|
* \retval #PSA_ERROR_NOT_SUPPORTED
|
|
* \p alg is not supported or is not a hash algorithm.
|
|
* \retval #PSA_ERROR_INVALID_ARGUMENT \emptydescription
|
|
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
|
|
* \p hash_size is too small
|
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_BAD_STATE
|
|
* The library has not been previously initialized by psa_crypto_init().
|
|
* It is implementation-dependent whether a failure to initialize
|
|
* results in this error code.
|
|
*/
|
|
psa_status_t psa_hash_compute(psa_algorithm_t alg,
|
|
const uint8_t *input,
|
|
size_t input_length,
|
|
uint8_t *hash,
|
|
size_t hash_size,
|
|
size_t *hash_length);
|
|
|
|
/* XXX We put this next one in place to check we ignore static functions
|
|
* when we eventually read all this from a real header file
|
|
*/
|
|
|
|
/** Return an initial value for a hash operation object.
|
|
*/
|
|
static psa_hash_operation_t psa_hash_operation_init(void);
|
|
|
|
/* XXX Back to normal function declarations */
|
|
|
|
/** Set up a multipart hash operation.
|
|
*
|
|
* The sequence of operations to calculate a hash (message digest)
|
|
* is as follows:
|
|
* -# Allocate an operation object which will be passed to all the functions
|
|
* listed here.
|
|
* -# Initialize the operation object with one of the methods described in the
|
|
* documentation for #psa_hash_operation_t, e.g. #PSA_HASH_OPERATION_INIT.
|
|
* -# Call psa_hash_setup() to specify the algorithm.
|
|
* -# Call psa_hash_update() zero, one or more times, passing a fragment
|
|
* of the message each time. The hash that is calculated is the hash
|
|
* of the concatenation of these messages in order.
|
|
* -# To calculate the hash, call psa_hash_finish().
|
|
* To compare the hash with an expected value, call psa_hash_verify().
|
|
*
|
|
* If an error occurs at any step after a call to psa_hash_setup(), the
|
|
* operation will need to be reset by a call to psa_hash_abort(). The
|
|
* application may call psa_hash_abort() at any time after the operation
|
|
* has been initialized.
|
|
*
|
|
* After a successful call to psa_hash_setup(), the application must
|
|
* eventually terminate the operation. The following events terminate an
|
|
* operation:
|
|
* - A successful call to psa_hash_finish() or psa_hash_verify().
|
|
* - A call to psa_hash_abort().
|
|
*
|
|
* \param[in,out] operation The operation object to set up. It must have
|
|
* been initialized as per the documentation for
|
|
* #psa_hash_operation_t and not yet in use.
|
|
* \param alg The hash algorithm to compute (\c PSA_ALG_XXX value
|
|
* such that #PSA_ALG_IS_HASH(\p alg) is true).
|
|
*
|
|
* \retval #PSA_SUCCESS
|
|
* Success.
|
|
* \retval #PSA_ERROR_NOT_SUPPORTED
|
|
* \p alg is not a supported hash algorithm.
|
|
* \retval #PSA_ERROR_INVALID_ARGUMENT
|
|
* \p alg is not a hash algorithm.
|
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_BAD_STATE
|
|
* The operation state is not valid (it must be inactive), or
|
|
* the library has not been previously initialized by psa_crypto_init().
|
|
* It is implementation-dependent whether a failure to initialize
|
|
* results in this error code.
|
|
*/
|
|
psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
|
|
psa_algorithm_t alg);
|
|
|
|
/** Add a message fragment to a multipart hash operation.
|
|
*
|
|
* The application must call psa_hash_setup() before calling this function.
|
|
*
|
|
* If this function returns an error status, the operation enters an error
|
|
* state and must be aborted by calling psa_hash_abort().
|
|
*
|
|
* \param[in,out] operation Active hash operation.
|
|
* \param[in] input Buffer containing the message fragment to hash.
|
|
* \param input_length Size of the \p input buffer in bytes.
|
|
*
|
|
* \retval #PSA_SUCCESS
|
|
* Success.
|
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_BAD_STATE
|
|
* The operation state is not valid (it must be active), or
|
|
* the library has not been previously initialized by psa_crypto_init().
|
|
* It is implementation-dependent whether a failure to initialize
|
|
* results in this error code.
|
|
*/
|
|
psa_status_t psa_hash_update(psa_hash_operation_t *operation,
|
|
const uint8_t *input,
|
|
size_t input_length);
|
|
|
|
/** Finish the calculation of the hash of a message.
|
|
*
|
|
* The application must call psa_hash_setup() before calling this function.
|
|
* This function calculates the hash of the message formed by concatenating
|
|
* the inputs passed to preceding calls to psa_hash_update().
|
|
*
|
|
* When this function returns successfully, the operation becomes inactive.
|
|
* If this function returns an error status, the operation enters an error
|
|
* state and must be aborted by calling psa_hash_abort().
|
|
*
|
|
* \warning Applications should not call this function if they expect
|
|
* a specific value for the hash. Call psa_hash_verify() instead.
|
|
* Beware that comparing integrity or authenticity data such as
|
|
* hash values with a function such as \c memcmp is risky
|
|
* because the time taken by the comparison may leak information
|
|
* about the hashed data which could allow an attacker to guess
|
|
* a valid hash and thereby bypass security controls.
|
|
*
|
|
* \param[in,out] operation Active hash operation.
|
|
* \param[out] hash Buffer where the hash is to be written.
|
|
* \param hash_size Size of the \p hash buffer in bytes.
|
|
* \param[out] hash_length On success, the number of bytes
|
|
* that make up the hash value. This is always
|
|
* #PSA_HASH_LENGTH(\c alg) where \c alg is the
|
|
* hash algorithm that is calculated.
|
|
*
|
|
* \retval #PSA_SUCCESS
|
|
* Success.
|
|
* \retval #PSA_ERROR_BUFFER_TOO_SMALL
|
|
* The size of the \p hash buffer is too small. You can determine a
|
|
* sufficient buffer size by calling #PSA_HASH_LENGTH(\c alg)
|
|
* where \c alg is the hash algorithm that is calculated.
|
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_BAD_STATE
|
|
* The operation state is not valid (it must be active), or
|
|
* the library has not been previously initialized by psa_crypto_init().
|
|
* It is implementation-dependent whether a failure to initialize
|
|
* results in this error code.
|
|
*/
|
|
psa_status_t psa_hash_finish(psa_hash_operation_t *operation,
|
|
uint8_t *hash,
|
|
size_t hash_size,
|
|
size_t *hash_length);
|
|
|
|
/** Finish the calculation of the hash of a message and compare it with
|
|
* an expected value.
|
|
*
|
|
* The application must call psa_hash_setup() before calling this function.
|
|
* This function calculates the hash of the message formed by concatenating
|
|
* the inputs passed to preceding calls to psa_hash_update(). It then
|
|
* compares the calculated hash with the expected hash passed as a
|
|
* parameter to this function.
|
|
*
|
|
* When this function returns successfully, the operation becomes inactive.
|
|
* If this function returns an error status, the operation enters an error
|
|
* state and must be aborted by calling psa_hash_abort().
|
|
*
|
|
* \note Implementations shall make the best effort to ensure that the
|
|
* comparison between the actual hash and the expected hash is performed
|
|
* in constant time.
|
|
*
|
|
* \param[in,out] operation Active hash operation.
|
|
* \param[in] hash Buffer containing the expected hash value.
|
|
* \param hash_length Size of the \p hash buffer in bytes.
|
|
*
|
|
* \retval #PSA_SUCCESS
|
|
* The expected hash is identical to the actual hash of the message.
|
|
* \retval #PSA_ERROR_INVALID_SIGNATURE
|
|
* The hash of the message was calculated successfully, but it
|
|
* differs from the expected hash.
|
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_BAD_STATE
|
|
* The operation state is not valid (it must be active), or
|
|
* the library has not been previously initialized by psa_crypto_init().
|
|
* It is implementation-dependent whether a failure to initialize
|
|
* results in this error code.
|
|
*/
|
|
psa_status_t psa_hash_verify(psa_hash_operation_t *operation,
|
|
const uint8_t *hash,
|
|
size_t hash_length);
|
|
|
|
/** Abort a hash operation.
|
|
*
|
|
* Aborting an operation frees all associated resources except for the
|
|
* \p operation structure itself. Once aborted, the operation object
|
|
* can be reused for another operation by calling
|
|
* psa_hash_setup() again.
|
|
*
|
|
* You may call this function any time after the operation object has
|
|
* been initialized by one of the methods described in #psa_hash_operation_t.
|
|
*
|
|
* In particular, calling psa_hash_abort() after the operation has been
|
|
* terminated by a call to psa_hash_abort(), psa_hash_finish() or
|
|
* psa_hash_verify() is safe and has no effect.
|
|
*
|
|
* \param[in,out] operation Initialized hash operation.
|
|
*
|
|
* \retval #PSA_SUCCESS \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_BAD_STATE
|
|
* The library has not been previously initialized by psa_crypto_init().
|
|
* It is implementation-dependent whether a failure to initialize
|
|
* results in this error code.
|
|
*/
|
|
psa_status_t psa_hash_abort(psa_hash_operation_t *operation);
|
|
|
|
/** Clone a hash operation.
|
|
*
|
|
* This function copies the state of an ongoing hash operation to
|
|
* a new operation object. In other words, this function is equivalent
|
|
* to calling psa_hash_setup() on \p target_operation with the same
|
|
* algorithm that \p source_operation was set up for, then
|
|
* psa_hash_update() on \p target_operation with the same input that
|
|
* that was passed to \p source_operation. After this function returns, the
|
|
* two objects are independent, i.e. subsequent calls involving one of
|
|
* the objects do not affect the other object.
|
|
*
|
|
* \param[in] source_operation The active hash operation to clone.
|
|
* \param[in,out] target_operation The operation object to set up.
|
|
* It must be initialized but not active.
|
|
*
|
|
* \retval #PSA_SUCCESS \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
|
|
* \retval #PSA_ERROR_BAD_STATE
|
|
* The \p source_operation state is not valid (it must be active), or
|
|
* the \p target_operation state is not valid (it must be inactive), or
|
|
* the library has not been previously initialized by psa_crypto_init().
|
|
* It is implementation-dependent whether a failure to initialize
|
|
* results in this error code.
|
|
*/
|
|
psa_status_t psa_hash_clone(const psa_hash_operation_t *source_operation,
|
|
psa_hash_operation_t *target_operation);
|
|
|
|
/** Calculate the hash (digest) of a message and compare it with a
|
|
* reference value.
|
|
*
|
|
* \param alg The hash algorithm to compute (\c PSA_ALG_XXX value
|
|
* such that #PSA_ALG_IS_HASH(\p alg) is true).
|
|
* \param[in] input Buffer containing the message to hash.
|
|
* \param input_length Size of the \p input buffer in bytes.
|
|
* \param[out] hash Buffer containing the expected hash value.
|
|
* \param hash_length Size of the \p hash buffer in bytes.
|
|
*
|
|
* \retval #PSA_SUCCESS
|
|
* The expected hash is identical to the actual hash of the input.
|
|
* \retval #PSA_ERROR_INVALID_SIGNATURE
|
|
* The hash of the message was calculated successfully, but it
|
|
* differs from the expected hash.
|
|
* \retval #PSA_ERROR_NOT_SUPPORTED
|
|
* \p alg is not supported or is not a hash algorithm.
|
|
* \retval #PSA_ERROR_INVALID_ARGUMENT
|
|
* \p input_length or \p hash_length do not match the hash size for \p alg
|
|
* \retval #PSA_ERROR_INSUFFICIENT_MEMORY \emptydescription
|
|
* \retval #PSA_ERROR_COMMUNICATION_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_HARDWARE_FAILURE \emptydescription
|
|
* \retval #PSA_ERROR_CORRUPTION_DETECTED \emptydescription
|
|
* \retval #PSA_ERROR_BAD_STATE
|
|
* The library has not been previously initialized by psa_crypto_init().
|
|
* It is implementation-dependent whether a failure to initialize
|
|
* results in this error code.
|
|
*/
|
|
psa_status_t psa_hash_compare(psa_algorithm_t alg,
|
|
const uint8_t *input,
|
|
size_t input_length,
|
|
const uint8_t *hash,
|
|
size_t hash_length);
|