1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-15 17:43:51 +01:00

sys: Add PSA Crypto Module

This commit is contained in:
Lena Boeckmann 2023-08-29 18:43:32 +02:00
parent 5cf32002f5
commit d4c73d6a30
43 changed files with 18742 additions and 0 deletions

View File

@ -0,0 +1,851 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
version="1.1"
width="500"
height="266"
id="svg1869"
sodipodi:docname="riot-psa-structure.svg"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview1871"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="1.9539249"
inkscape:cx="187.82707"
inkscape:cy="175.28821"
inkscape:window-width="2556"
inkscape:window-height="1396"
inkscape:window-x="0"
inkscape:window-y="20"
inkscape:window-maximized="1"
inkscape:current-layer="gnrc-detail" />
<title
id="title1749">RIOT's GNRC Network Stack</title>
<metadata
id="metadata1751">
<rdf:RDF>
<cc:Work
rdf:about="Provides a general overview over RIOT's GNRC Network Stack">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>RIOT's GNRC Network Stack</dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
<dc:creator>
<cc:Agent>
<dc:title>Cenk Gündoğan</dc:title>
</cc:Agent>
<cc:Agent>
<dc:title>Martine Lenders</dc:title>
</cc:Agent>
</dc:creator>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs1779">
<style
type="text/css"
id="style1753"><![CDATA[
@font-face {
font-family: 'Miso';
font-style: normal;
font-weight: normal;
src: url('miso.eot'); /* IE 9 Compatibility Mode */
src: url('miso.eot?#iefix') format('embedded-opentype'), /* IE < 9 */
url('data:application/x-font-woff;charset=utf-8;base64, \
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 \
') format('woff'), /* Firefox >= 3.6, any other modern browser */
url('miso.ttf') format('truetype'), /* Safari, Android, iOS */
url('miso.svg#Miso') format('svg'); /* Chrome < 4, Legacy iOS */
}
.modbox-text {
line-height: 125%;
fill: #ffffff;
font-family: 'Miso';
font-size: 28px;
text-anchor: middle;
}
.modbox {
fill: #275a4b;
stroke: #3fa687;
stroke-linecap: round;
stroke-linejoin: round;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-text {
line-height: 125%;
fill: #3fa687;
font-family: 'Miso';
font-size: 32px;
text-anchor: middle;
}
.outer-text-netapi {
line-height: 125%;
fill: #3fa687;
font-family: 'Miso';
font-size: 28px;
text-anchor: start;
}
.outer-stroke {
fill: none;
stroke: #3fa687;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
#gnrc-detail-sock {
fill: none;
stroke: url(#outer-gradient-sock);
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
#gnrc-detail-netdev {
fill: none;
stroke: url(#outer-gradient-netdev);
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-stroke-dashed {
fill: none;
stroke: #3fa687;
stroke-dasharray: 9, 9;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-stroke-dotted {
fill: none;
stroke: #3fa687;
stroke-dasharray: 1, 5;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-stroke-arrow {
fill: none;
marker-start: url(#arrow-start);
marker-end: url(#arrow-end);
stroke: #3fa687;
stroke-linecap: round;
stroke-linejoin: miter;
stroke-miterlimit: 4;
stroke-width: 3;
}
.outer-arrow-head {
fill: #3fa687;
fill-rule: evenodd;
stroke: #3fa687;
stroke-width: 1pt;
}
]]></style>
<linearGradient
id="outer-gradient-sock"
x1="-0.44030017"
y1="-5.1101503"
x2="-0.44030017"
y2="107.31316"
gradientTransform="scale(3.4067669,0.29353344)"
gradientUnits="userSpaceOnUse">
<stop
style="stop-color: #3fa687; stop-opacity: 0;"
offset="0"
id="stop1755" />
<stop
style="stop-color: #3fa687; stop-opacity: 0;"
offset="0.1"
id="stop1757" />
<stop
style="stop-color: #3fa687; stop-opacity: 1;"
offset="0.9"
id="stop1759" />
<stop
style="stop-color: #3fa687; stop-opacity: 1;"
offset="1"
id="stop1761" />
</linearGradient>
<linearGradient
id="outer-gradient-netdev"
x1="-0.44030017"
y1="1221.3259"
x2="-0.44030017"
y2="1333.7491"
gradientTransform="scale(3.4067669,0.29353344)"
gradientUnits="userSpaceOnUse">
<stop
style="stop-color: #3fa687; stop-opacity: 1;"
offset="0"
id="stop1764" />
<stop
style="stop-color: #3fa687; stop-opacity: 1;"
offset="0.1"
id="stop1766" />
<stop
style="stop-color: #3fa687; stop-opacity: 0;"
offset="0.9"
id="stop1768" />
<stop
style="stop-color: #3fa687; stop-opacity: 0;"
offset="1"
id="stop1770" />
</linearGradient>
<marker
style="overflow:visible"
id="arrow-start"
orient="auto">
<path
class="outer-arrow-head"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
transform="matrix(0.2,0,0,0.2,1.2,0)"
id="path1773" />
</marker>
<marker
style="overflow:visible"
id="arrow-end"
orient="auto">
<path
class="outer-arrow-head"
d="M 0,0 5,-5 -12.5,0 5,5 Z"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)"
id="path1776" />
</marker>
</defs>
<g
id="gnrc-detail"
transform="matrix(0.75,0,0,0.75,3.75,0)">
<g
id="g8922">
<rect
id="gnrc-sock-box"
class="modbox"
x="9.759263"
y="17.349091"
rx="7.0792012"
ry="4.0499377"
width="637.12817"
height="50.624222"
style="stroke-width:2.70911;stroke-dasharray:none" />
<text
id="gnrc-sock-label"
class="modbox-text"
x="328.18332"
y="51.050667"><tspan
id="tspan1785">PSA Crypto</tspan></text>
</g>
<g
id="g3901"
transform="matrix(0.99993339,0,0,1.0321558,-0.71650498,84.465735)"
style="stroke-width:2.62489;stroke-dasharray:none">
<rect
id="gnrc-sock-box-6"
class="modbox"
x="10.476466"
y="0.47646618"
rx="7.0796728"
ry="3.9237654"
width="637.17059"
height="49.04707"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.62489;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7"
class="modbox-text"
x="328.92175"
y="32"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff;stroke-width:2.62489;stroke-dasharray:none"><tspan
id="tspan1785-5"
style="stroke-width:2.62489;stroke-dasharray:none">Key Management and Location Dispatch</tspan></text>
</g>
<g
id="g3896"
transform="translate(43.403416,87.323162)">
<rect
id="gnrc-sock-box-6-5"
class="modbox"
x="293.2406"
y="65.227448"
rx="3.4473193"
ry="4.052392"
width="310.25876"
height="50.6549"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.67843;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6"
class="modbox-text"
x="448.90601"
y="97.554901"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2">Algorithm Dispatch</tspan></text>
</g>
<g
id="g3896-2"
transform="matrix(0.99996209,0,0,1.0088791,43.420411,154.13341)">
<rect
id="gnrc-sock-box-6-5-0"
class="modbox"
x="293.23471"
y="65.450356"
rx="3.4474499"
ry="4.016727"
width="310.27051"
height="50.209087"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-23"
class="modbox-text"
x="448.90601"
y="97.554901"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-75">Spec. Algorithm API</tspan></text>
</g>
<g
id="g7406"
transform="matrix(0.99996307,0,0,1.0086479,0.00608848,0.69035637)">
<rect
id="gnrc-sock-box-6-5-1"
class="modbox"
x="9.7380409"
y="150.56415"
rx="3.4474499"
ry="4.016727"
width="310.27051"
height="50.209087"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2"
class="modbox-text"
x="164.89879"
y="182.05269"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-7">SE Dispatch</tspan></text>
</g>
<g
id="g5505"
transform="matrix(1.0002158,0,0,0.98547915,-282.22812,86.706483)">
<rect
id="gnrc-sock-box-6-5-1-9"
class="modbox"
x="291.89359"
y="135.4252"
rx="0.98559189"
ry="4.1146121"
width="88.70327"
height="51.432655"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3"
class="modbox-text"
x="336.57822"
y="170.04283"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-7-6">SE API</tspan></text>
</g>
<g
id="g5505-0"
transform="matrix(1.0002158,0,0,0.98547915,-172.47439,86.706483)">
<rect
id="gnrc-sock-box-6-5-1-9-6"
class="modbox"
x="291.89359"
y="135.4252"
rx="0.98559189"
ry="4.1146121"
width="88.70327"
height="51.432655"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-2"
class="modbox-text"
x="336.57822"
y="170.04283"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-7-6-6">SE API</tspan></text>
</g>
<g
id="g5505-1"
transform="matrix(1.0002158,0,0,0.98547915,-62.864627,86.706483)">
<rect
id="gnrc-sock-box-6-5-1-9-8"
class="modbox"
x="291.89359"
y="135.4252"
rx="0.98559189"
ry="4.1146121"
width="88.70327"
height="51.432655"
style="fill:#275a4b;stroke:#3fa687;stroke-width:2.66667;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-7"
class="modbox-text"
x="336.57822"
y="170.04283"
style="font-size:28px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#ffffff"><tspan
id="tspan1785-5-2-7-6-9">SE API</tspan></text>
</g>
<rect
id="gnrc-sock-box-6-5-1-9-2"
class="modbox"
x="9.7284555"
y="287.78241"
rx="0.98580456"
ry="4.0548644"
width="88.722412"
height="50.68581"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.64752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-8"
class="modbox-text"
x="54.020325"
y="324.29523"
style="font-size:27.799px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:0.99282"
transform="scale(1.0074492,0.99260593)"><tspan
id="tspan1785-5-2-7-6-97"
style="fill:#275a4b;fill-opacity:1;stroke-width:0.99282">SE1 Drv</tspan></text>
<rect
id="gnrc-sock-box-6-5-1-9-6-6"
class="modbox"
x="119.48219"
y="287.78241"
rx="0.98580456"
ry="4.0548644"
width="88.722412"
height="50.68581"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.64752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-2-1"
class="modbox-text"
x="162.96252"
y="324.29523"
style="font-size:27.799px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:0.99282"
transform="scale(1.0074492,0.99260593)"><tspan
id="tspan1785-5-2-7-6-6-2"
style="fill:#275a4b;fill-opacity:1;stroke-width:0.99282">SE2 Drv</tspan></text>
<rect
id="gnrc-sock-box-6-5-1-9-8-3"
class="modbox"
x="229.09195"
y="287.78241"
rx="0.98580456"
ry="4.0548644"
width="88.722412"
height="50.68581"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.64752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-7-1"
class="modbox-text"
x="271.76184"
y="324.29523"
style="font-size:27.799px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:0.99282"
transform="scale(1.0074492,0.99260593)"><tspan
id="tspan1785-5-2-7-6-9-9"
style="fill:#275a4b;fill-opacity:1;stroke-width:0.99282">SE3 Drv</tspan></text>
<rect
id="gnrc-sock-box-6-5-1-9-6-6-7"
class="modbox"
x="337.05817"
y="287.77283"
rx="1.6380999"
ry="4.0533733"
width="147.429"
height="50.667171"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.66617;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-2-1-8"
class="modbox-text"
x="410.22644"
y="322.06619"
style="font-size:27.9947px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:2.66617;stroke-dasharray:none"
transform="scale(1.0001922,0.99980782)"><tspan
id="tspan1785-5-2-7-6-6-2-4"
style="fill:#275a4b;fill-opacity:1;stroke-width:2.66617;stroke-dasharray:none">HW Drv</tspan></text>
<rect
id="gnrc-sock-box-6-5-1-9-6-6-7-0"
class="modbox"
x="499.10678"
y="287.7822"
rx="1.6380999"
ry="4.0533733"
width="147.429"
height="50.667171"
style="fill:#b6e0d3;fill-opacity:1;stroke:#3fa687;stroke-width:2.66617;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none" />
<text
id="gnrc-sock-label-7-6-2-3-2-1-8-6"
class="modbox-text"
x="572.2439"
y="322.07556"
style="font-size:27.9947px;line-height:125%;font-family:Miso;text-anchor:middle;fill:#275a4b;fill-opacity:1;stroke-width:0.999811"
transform="scale(1.0001922,0.99980782)"><tspan
id="tspan1785-5-2-7-6-6-2-4-1"
style="fill:#275a4b;fill-opacity:1;stroke-width:0.999811">SW Library</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -93,4 +93,12 @@ else
"don't run this on public networks!$(COLOR_RESET)" 1>&2)
endif
endif
# Warn about PSA Crypto
ifneq (,$(filter psa_crypto,$(USEMODULE)))
$(shell $(COLOR_ECHO) "$(COLOR_YELLOW) You are going to use the PSA Crypto module,"\
"which is only partly implemented and not yet thouroughly tested.\n"\
"Please do not use this module in production, as it may introduce"\
"security issues!$(COLOR_RESET)" 1>&2)
endif
endif

View File

@ -93,6 +93,7 @@ rsource "posix/Kconfig"
rsource "preprocessor/Kconfig"
rsource "progress_bar/Kconfig"
rsource "ps/Kconfig"
rsource "psa_crypto/Kconfig"
rsource "random/Kconfig"
rsource "rtc_utils/Kconfig"
rsource "rust_riotmodules/Kconfig"

View File

@ -173,6 +173,9 @@ endif
ifneq (,$(filter posix_sleep,$(USEMODULE)))
DIRS += posix/sleep
endif
ifneq (,$(filter psa_crypto,$(USEMODULE)))
DIRS += psa_crypto
endif
ifneq (,$(filter pthread,$(USEMODULE)))
DIRS += posix/pthread
endif

View File

@ -686,6 +686,14 @@ ifneq (,$(filter fido2_ctap%,$(USEMODULE)))
USEMODULE += fido2
endif
ifneq (,$(filter psa_crypto,$(USEMODULE)))
include $(RIOTBASE)/sys/psa_crypto/Makefile.dep
endif
ifneq (,$(filter psa_riot_cipher_aes_%,$(USEMODULE)))
USEMODULE += psa_riot_cipher_aes_common
endif
ifneq (,$(filter rust_riotmodules,$(USEMODULE)))
include $(RIOTBASE)/sys/rust_riotmodules/Makefile.dep
endif

View File

@ -163,6 +163,10 @@ ifneq (,$(filter prng,$(USEMODULE)))
include $(RIOTBASE)/sys/random/Makefile.include
endif
ifneq (,$(filter psa_crypto,$(USEMODULE)))
include $(RIOTBASE)/sys/psa_crypto/Makefile.include
endif
ifneq (,$(filter test_utils_netdev_eth_minimal,$(USEMODULE)))
CFLAGS += -DCONFIG_NETDEV_REGISTER_SIGNAL
endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file crypto_contexts.h
* @brief Context definitions for PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H
#define PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "kernel_defines.h"
#include "psa/crypto_includes.h"
#if IS_USED(MODULE_PSA_HASH)
/**
* @brief Structure containing the hash contexts needed by the application.
*/
typedef union {
#if IS_USED(MODULE_PSA_HASH_MD5) || defined(DOXYGEN)
psa_hashes_md5_ctx_t md5; /**< MD5 context */
#endif
#if IS_USED(MODULE_PSA_HASH_SHA_1) || defined(DOXYGEN)
psa_hashes_sha1_ctx_t sha1; /**< SHA-1 context */
#endif
#if IS_USED(MODULE_PSA_HASH_SHA_224) || defined(DOXYGEN)
psa_hashes_sha224_ctx_t sha224; /**< SHA-224 context */
#endif
#if IS_USED(MODULE_PSA_HASH_SHA_256) || defined(DOXYGEN)
psa_hashes_sha256_ctx_t sha256; /**< SHA-256 context */
#endif
#if IS_USED(MODULE_PSA_HASH_SHA_512) || defined(DOXYGEN)
psa_hashes_sha512_ctx_t sha512; /**< SHA-512 context */
#endif
} psa_hash_context_t;
#endif
#if IS_USED(MODULE_PSA_CIPHER)
/**
* @brief Structure containing the cipher contexts needed by the application.
*/
typedef union {
#if IS_USED(MODULE_PSA_CIPHER_AES_128_ECB) ||\
IS_USED(MODULE_PSA_CIPHER_AES_128_CBC) ||\
defined(DOXYGEN)
psa_cipher_aes_128_ctx_t aes_128; /**< AES 128 context*/
#endif
#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC) || defined(DOXYGEN)
psa_cipher_aes_192_ctx_t aes_192; /**< AES 192 context*/
#endif
#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC) || defined(DOXYGEN)
psa_cipher_aes_256_ctx_t aes_256; /**< AES 256 context*/
#endif
} psa_cipher_context_t;
#endif
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
/**
* @brief Structure containing the secure element specific cipher contexts needed by the
* application.
*/
typedef struct {
psa_encrypt_or_decrypt_t direction; /**< Direction of this cipher operation */
/** Structure containing a driver specific cipher context */
union driver_context {
unsigned dummy; /**< Make the union non-empty even with no supported algorithms. */
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN)
atca_aes_cbc_ctx_t atca_aes_cbc; /**< ATCA AES CBC context*/
#endif
} drv_ctx; /**< SE specific cipher operation context */
} psa_se_cipher_context_t;
#endif
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_PSA_CRYPTO_CONTEXTS_H */
/** @} */

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @brief Files to include in the build of PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H
#define PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H
#ifdef __cplusplus
extern "C" {
#endif
#include "kernel_defines.h"
#if IS_USED(MODULE_CRYPTO)
#include "crypto/psa/riot_ciphers.h"
#endif
#if IS_USED(MODULE_PSA_RIOT_HASHES_HMAC_SHA256) || IS_USED(MODULE_PSA_RIOT_HASHES_MD5) || \
IS_USED(MODULE_PSA_RIOT_HASHES_SHA_1) || IS_USED(MODULE_PSA_RIOT_HASHES_SHA_224) || \
IS_USED(MODULE_PSA_RIOT_HASHES_SHA_256)
#include "hashes/psa/riot_hashes.h"
#endif
#if IS_USED(MODULE_PERIPH_CIPHER_AES_128_CBC)
#include "psa_periph_aes_ctx.h"
#endif
#if IS_USED(MODULE_PERIPH_HASH_SHA_1) || IS_USED(MODULE_PERIPH_HASH_SHA_224) || \
IS_USED(MODULE_PERIPH_HASH_SHA_256) || IS_USED(MODULE_PERIPH_HASH_SHA_512)
#include "psa_periph_hashes_ctx.h"
#endif
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
#include "atca_params.h"
#endif
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_PSA_CRYPTO_INCLUDES_H */
/** @} */

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2023 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file
* @brief Define structures für SE slot configurations
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H
#define PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
#include "atca.h"
#endif
/**
* @brief Structure containing device specific configuration data.
*
* This will be stored in the driver's persistent data to
* manage the device.
*/
typedef union {
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A)
psa_atca_slot_config_t slots[16];
#endif
} psa_se_config_t;
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_PSA_CRYPTO_SE_CONFIG_H */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,224 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file crypto_struct.h
* @brief Structure definitions for PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_PSA_CRYPTO_STRUCT_H
#define PSA_CRYPTO_PSA_CRYPTO_STRUCT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "crypto_types.h"
#include "crypto_sizes.h"
#include "crypto_contexts.h"
/**
* @brief Structure containing a hash context and algorithm
*/
struct psa_hash_operation_s {
psa_algorithm_t alg; /**< Operation algorithm */
#if IS_USED(MODULE_PSA_HASH)
psa_hash_context_t ctx; /**< Operation hash context */
#endif
};
/**
* @brief This macro returns a suitable initializer for a hash operation object of type
* @ref psa_hash_operation_t.
*/
#define PSA_HASH_OPERATION_INIT { 0 }
/**
* @brief Return an initial value for a hash operation object.
*
* @return struct psa_hash_operation_s
*/
static inline struct psa_hash_operation_s psa_hash_operation_init(void)
{
const struct psa_hash_operation_s v = PSA_HASH_OPERATION_INIT;
return v;
}
/**
* @brief Structure storing the key usage policies
*/
struct psa_key_policy_s {
psa_key_usage_t usage; /**< Key usage policy */
psa_algorithm_t alg; /**< Algorithm for key usage */
};
/**
* @brief Type for key usage policies.
*/
typedef struct psa_key_policy_s psa_key_policy_t;
/**
* @brief Structure storing key attributes
*/
struct psa_key_attributes_s {
psa_key_type_t type; /**< Type of key */
psa_key_bits_t bits; /**< Size of key in bits */
psa_key_lifetime_t lifetime; /**< Lifetime of key */
psa_key_id_t id; /**< Key identifier */
psa_key_policy_t policy; /**< Key usage policy */
};
/**
* @brief This macro returns a suitable initializer for a key attribute object of
* type @ref psa_key_attributes_t.
*/
#define PSA_KEY_ATTRIBUTES_INIT { 0 }
/**
* @brief Return an initial value for a key attribute object.
*
* @return struct psa_key_attributes_s
*/
static inline struct psa_key_attributes_s psa_key_attributes_init(void)
{
const struct psa_key_attributes_s v = PSA_KEY_ATTRIBUTES_INIT;
return v;
}
/**
* @brief Structure storing an AEAD operation context
*
* @note Not implemented, yet
*/
struct psa_aead_operation_s {
int dummy; /**< Not implemented, yet */
};
/**
* @brief This macro returns a suitable initializer for an AEAD operation object of type
* @ref psa_aead_operation_t.
*/
#define PSA_AEAD_OPERATION_INIT { 0 }
/**
* @brief Return an initial value for an AEAD operation object.
*
* @return psa_aead_operation_s
*/
static inline struct psa_aead_operation_s psa_aead_operation_init(void)
{
const struct psa_aead_operation_s v = PSA_AEAD_OPERATION_INIT;
return v;
}
/**
* @brief Structure storing a cipher operation context
*/
struct psa_cipher_operation_s {
uint8_t iv_required : 1; /**< True if algorithm requires IV */
uint8_t iv_set : 1; /**< True if IV was already set */
uint8_t default_iv_length; /**< Default IV length for algorithm */
psa_algorithm_t alg; /**< Operation algorithm*/
/** Union containing cipher contexts for the executing backend */
union cipher_context {
#if IS_USED(MODULE_PSA_CIPHER)
psa_cipher_context_t cipher_ctx; /**< Cipher context */
#endif
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN)
psa_se_cipher_context_t se_ctx; /**< SE Cipher context */
#endif
} backend_ctx; /**< Backend specific cipher context */
};
/**
* @brief This macro returns a suitable initializer for a cipher operation
* object of type @ref psa_cipher_operation_t.
*/
#define PSA_CIPHER_OPERATION_INIT { 0 }
/**
* @brief Return an initial value for a cipher operation object.
*
* @return psa_cipher_operation_s
*/
static inline struct psa_cipher_operation_s psa_cipher_operation_init(void)
{
const struct psa_cipher_operation_s v = PSA_CIPHER_OPERATION_INIT;
return v;
}
/**
* @brief This macro returns a suitable initializer for a key derivation operation object of
* type @ref psa_key_derivation_operation_t.
*/
#define PSA_KEY_DERIVATION_OPERATION_INIT { 0 }
/**
* @brief Structure storing a key derivation context
*
* @note Not yet implemented
*/
struct psa_key_derivation_operation_s {
int dummy; /**< Not implemented yet */
};
/**
* @brief Return an initial value for a key derivation operation object.
*
* @return psa_key_derivation_operation_s
*/
static inline struct psa_key_derivation_operation_s psa_key_derivation_operation_init(void)
{
const struct psa_key_derivation_operation_s v = PSA_KEY_DERIVATION_OPERATION_INIT;
return v;
}
/**
* @brief This macro returns a suitable initializer for a MAC operation object of type
* @ref psa_mac_operation_t.
*/
#define PSA_MAC_OPERATION_INIT { 0 }
/**
* @brief Structure storing a MAC operation context
*
* @note Not yet implemented
*/
struct psa_mac_operation_s {
int dummy; /**< Not yet implemented */
};
/**
* @brief Return an initial value for a MAC operation object.
*
* @return psa_mac_operation_s
*/
static inline struct psa_mac_operation_s psa_mac_operation_init(void)
{
const struct psa_mac_operation_s v = PSA_MAC_OPERATION_INIT;
return v;
}
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_PSA_CRYPTO_STRUCT_H */
/** @} */

View File

@ -0,0 +1,503 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file crypto_types.h
* @brief Type definitions for PSA Crypto
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_PSA_CRYPTO_TYPES_H
#define PSA_CRYPTO_PSA_CRYPTO_TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* @brief For encrypt-decrypt functions, whether the operation is an encryption
* or a decryption.
*/
typedef enum {
PSA_CRYPTO_DRIVER_DECRYPT,
PSA_CRYPTO_DRIVER_ENCRYPT
} psa_encrypt_or_decrypt_t;
/**
* @brief Encoding of a cryptographic algorithm.
*
* @details For algorithms that can be applied to multiple key types, this identifier does not
* encode the key type. For example, for symmetric ciphers based on a block cipher,
* @ref psa_algorithm_t encodes the block cipher mode and the padding mode while the
* block cipher itself is encoded via @ref psa_key_type_t.
*/
typedef uint32_t psa_algorithm_t;
/**
* @brief The type of PSA finite-field Diffie-Hellman group family identifiers.
*
* @details The group family identifier is required to create a finite-field Diffie-Hellman
* key using the @ref PSA_KEY_TYPE_DH_KEY_PAIR() or @ref PSA_KEY_TYPE_DH_PUBLIC_KEY()
* macros.
*
* The specific Diffie-Hellman group within a family is identified by the @c key_bits
* attribute of the key.
*/
typedef uint8_t psa_dh_family_t;
/**
* @brief The type of PSA elliptic curve family identifiers.
*
* @details The curve identifier is required to create an ECC key using the
* @ref PSA_KEY_TYPE_ECC_KEY_PAIR() or @ref PSA_KEY_TYPE_ECC_PUBLIC_KEY()
* macros.
*
* The specific ECC curve within a family is identified by the @c key_bits
* attribute of the key.
*/
typedef uint8_t psa_ecc_family_t;
/**
* @brief The type of the state object for key derivation operations.
*
* @details Before calling any function on a key derivation operation object, the application must
* initialize it by any of the following means:
* - Set the object to all-bits-zero, for example:
* @code
* @ref psa_key_derivation_operation_t operation;
* memset(&operation, 0, sizeof(operation));
* @endcode
* - Initialize the object to logical zero values by declaring the object as static or
* global without an explicit initializer, for example:
* @code
* static @ref psa_key_derivation_operation_t operation;
* @endcode
* - Initialize the object to the initializer @ref PSA_KEY_DERIVATION_OPERATION_INIT,
* for example:
* @code
* @ref psa_key_derivation_operation_t operation =
* @ref PSA_KEY_DERIVATION_OPERATION_INIT;
* @endcode
* - Assign the result of the function @ref psa_key_derivation_operation_init() to
* the object, for example:
* @code
* @ref psa_key_derivation_operation_t operation;
* operation = @ref psa_key_derivation_operation_init();
* @endcode
* This is an implementation-defined type. Applications that make assumptions about the
* content of this object will result in in implementation-specific behavior, and are
* non-portable.
*/
typedef struct psa_key_derivation_operation_s psa_key_derivation_operation_t;
/**
* @brief Encoding of the step of a key derivation.
*/
typedef uint16_t psa_key_derivation_step_t;
/**
* @brief Key identifier.
*
* @details A key identifier can be a permanent name for a persistent key, or a transient reference
* to volatile key.
*/
typedef uint32_t psa_key_id_t;
/**
* @brief Encoding of key lifetimes.
*
* @details The lifetime of a key indicates where it is stored and which application and system
* actions will create and destroy it.
*
* Lifetime values have the following structure:
* - Bits[7:0]: Persistence level
* This value indicates what device management actions can cause it to be destroyed.
* In particular, it indicates whether the key is volatile or persistent.
* See @ref psa_key_persistence_t for more information.
* @ref PSA_KEY_LIFETIME_GET_PERSISTENCE(@p lifetime) returns the persistence level for
* a key lifetime value.
* - Bits[31:8]: Location indicator
* This value indicates where the key material is stored (or at least where it is
* accessible in cleartext) and where operations on the key are performed. See
* @ref psa_key_location_t for more information.
* @ref PSA_KEY_LIFETIME_GET_LOCATION(@p lifetime) returns the location indicator for a
* key lifetime value.
*
* Volatile keys are automatically destroyed when the application instance terminates or
* on a power reset of the device. Persistent keys are preserved until the application
* explicitly destroys them or until an implementation-specific device management event
* occurs, for example, a factor reset.
*
* Persistent keys have a key identifier of type @ref psa_key_id_t. This identifier
* remains valid throughout the lifetime of the key, even if the application instance
* that created the key terminates.
*
* This specification defines two basic lifetime values:
* - Keys with the lifetime @ref PSA_KEY_LIFETIME_VOLATILE are volatile. All
* implementations should support this lifetime.
* - Keys with the lifetime @ref PSA_KEY_LIFETIME_PERSISTENT are persistent. All
* implementations that have access to persistent storage with appropriate security
* guarantees should support this lifetime.
*/
typedef uint32_t psa_key_lifetime_t;
/**
* @brief Encoding of key location indicators.
*
* @details If an implementation of this API can make calls to external cryptoprocessors such as
* secure elements, the location of a key indicates which secure element performs the
* operations on the key. If the key material is not stored persistently inside the secure
* element, it must be stored in a wrapped form such that only the secure element can
* access the key material in cleartext.
*
* @note Key location indicators are 24-bit values. Key management interfaces operate on
* lifetimes (type @ref psa_key_lifetime_t), and encode the location as the upper 24 bits
* of a 32-bit value.
*
* Values for location indicators defined by this specification are shown below:
* - @c 0: Primary local storage.
* All implementations should support this value. The primary local storage is
* typically the same storage area that contains the key metadata.
* - @c 1: Primary secure element.
* @note As of now, this value is not supported by this implementation.
* Use the vendor-defined location values.
*
* Implementations should support this value if there is a secure element
* attached to the operating environment. As a guideline, secure elements may
* provide higher resistance against side channel and physical attacks than the
* primary local storage, but may have restrictions on supported key types,
* sizes, policies and operations and may have different performance
* characteristics.
* - @c 20x7fffff: Other locations defined by a PSA specification.
* The PSA Cryptography API does not currently assign any meaning to
* these locations, but future versions of this specification or other
* PSA specifications may do so.
* - @c 0x8000000xffffff: Vendor-defined locations. No PSA specification will assign a
* meaning to locations in this range.
*/
typedef uint32_t psa_key_location_t;
/**
* @brief Encoding of key persistence levels.
*
* @details What distinguishes different persistence levels is which device management events can
* cause keys to be destroyed. For example, power reset, transfer of device ownership,
* or a factory reset are device management events that can affect keys at different
* persistence levels. The specific management events which affect persistent keys at
* different levels is outside the scope of the PSA Cryptography specification.
*
* @note Key persistence levels are 8-bit values. Key management interfaces operate on lifetimes
* (type @ref psa_key_lifetime_t), and encode the persistence value as the lower 8 bits of
* a 32-bit value.
*
* Values for persistence levels defined by this specification are shown below:
* - @c 0 = @ref PSA_KEY_PERSISTENCE_VOLATILE : Volatile key.
* A volatile key is automatically destroyed by the implementation when the
* application instance terminates. In particular, a volatile key is
* automatically destroyed on a power reset of the device.
* - @c 1 = @ref PSA_KEY_PERSISTENCE_DEFAULT : Persistent key with a default lifetime.
* Implementations should support this value if they support persistent keys
* at all. Applications should use this value if they have no specific needs
* that are only met by implementation-specific features.
* - @c 2127: Persistent key with a PSA-specified lifetime. The PSA Cryptography
* specification does not define the meaning of these values, but other PSA
* specifications may do so.
* - @c 128254: Persistent key with a vendor-specified lifetime. No PSA specification
* will define the meaning of these values, so implementations may choose
* the meaning freely. As a guideline, higher persistence levels should
* cause a key to survive more management events than lower levels.
* - @c 255 = @ref PSA_KEY_PERSISTENCE_READ_ONLY : Read-only or write-once key.
* A key with this persistence level cannot be destroyed. Implementations that
* support such keys may either allow their creation through the PSA
* Cryptography API, preferably only to applications with the appropriate
* privilege, or only expose keys created through implementation-specific
* means such as a factory ROM engraving process.
* @note Keys that are read-only due to policy restrictions rather than
* due to physical limitations should not have this persistence level.
*/
typedef uint8_t psa_key_persistence_t;
/**
* @brief Encoding of a key type.
*
* @details This is a structured bitfield that identifies the category and type of key. The range
* of key type values is divided as follows:
* - @ref PSA_KEY_TYPE_NONE == @c 0:
* Reserved as an invalid key type.
* - @c 0x00010x7fff:
* Specification-defined key types. Key types defined by this standard always have bit
* 15 clear. Unallocated key type values in this range are reserved for future use.
* - @c 0x80000xffff:
* Implementation-defined key types. Implementations that define additional key types
* must use an encoding with bit 15 set.
*/
typedef uint16_t psa_key_type_t;
/**
* @brief Encoding of permitted usage on a key.
*/
typedef uint32_t psa_key_usage_t;
/**
* @brief Public interfaces use @c size_t, but internally we use a smaller type.
*/
typedef uint16_t psa_key_bits_t;
/* These are all temporarily defined as some numeric type to prevent errors at compile time.*/
/**
* @brief The type of the state object for multi-part AEAD operations.
*
* @details Before calling any function on an AEAD operation object, the application must
* initialize it by any of the following means:
* - Set the object to all-bits-zero, for example:
* @code
* @ref psa_aead_operation_t operation;
* memset(&operation, 0, sizeof(operation));
* @endcode
* - Initialize the object to logical zero values by declaring the object as static
* or global without an explicit initializer, for example:
* @code
* static @ref psa_aead_operation_t operation;
* @endcode
* - Initialize the object to the initializer @ref PSA_AEAD_OPERATION_INIT, for example:
* @code
* @ref psa_aead_operation_t operation = @ref PSA_AEAD_OPERATION_INIT;
* @endcode
* - Assign the result of the function @ref psa_aead_operation_init() to the object,
* for example:
* @code
* @ref psa_aead_operation_t operation;
* operation = @ref psa_aead_operation_init();
* @endcode
*
* This is an implementation-defined type. Applications that make assumptions about the
* content of this object will result in in implementation-specific behavior, and are
* non-portable.
*/
typedef struct psa_aead_operation_s psa_aead_operation_t;
/**
* @brief The type of the state object for multi-part MAC operations.
*
* @details Before calling any function on a MAC operation object, the application must initialize
* it by any of the following means:
* - Set the object to all-bits-zero, for example:
* @code
* @ref psa_mac_operation_t operation;
* memset(&operation, 0, sizeof(operation));
* @endcode
* - Initialize the object to logical zero values by declaring the object as static or
* global without an explicit initializer, for example:
* @code
* static @ref psa_mac_operation_t operation;
* @endcode
* - Initialize the object to the initializer @ref PSA_MAC_OPERATION_INIT, for example:
* @code
* @ref psa_mac_operation_t operation = @ref PSA_MAC_OPERATION_INIT;
* @endcode
* - Assign the result of the function @ref psa_mac_operation_init() to the object,
* for example:
* @code
* @ref psa_mac_operation_t operation;
* operation = @ref psa_mac_operation_init();
* @endcode
* This is an implementation-defined type. Applications that make assumptions about the
* content of this object will result in in implementation-specific behavior, and are
* non-portable.
*/
typedef struct psa_mac_operation_s psa_mac_operation_t;
/**
* @brief Function return status.
*
* @details This is either @ref PSA_SUCCESS, which is zero, indicating success; or a small
* negative value indicating that an error occurred. Errors are encoded as one of
* the @c PSA_ERROR_xxx values defined here.
*/
typedef int32_t psa_status_t;
/**
* @brief The type of the state data structure for multipart hash operations.
*
* @details Before calling any function on a hash operation object, the application must
* initialize it by any of the following means:
* - Set the structure to all-bits-zero, for example:
* @code
* @ref psa_hash_operation_t operation;
* memset(&operation, 0, sizeof(operation));
* @endcode
* - Initialize the structure to logical zero values, for example:
* @code
* @ref psa_hash_operation_t operation = {0};
* @endcode
* - Initialize the structure to the initializer @ref PSA_HASH_OPERATION_INIT,
* for example:
* @code
* @ref psa_hash_operation_t operation = @ref PSA_HASH_OPERATION_INIT;
* @endcode
* - Assign the result of the function @ref psa_hash_operation_init()
* to the structure, for example:
* @code
* @ref psa_hash_operation_t operation;
* operation = @ref psa_hash_operation_init();
* @endcode
*
* This is an implementation-defined struct. Applications should not
* make any assumptions about the content of this structure except
* as directed by the documentation of a specific implementation.
*/
typedef struct psa_hash_operation_s psa_hash_operation_t;
/**
* @brief The type of an object containing key attributes.
*
* @details This is the object that represents the metadata of a key object. Metadata that can be
* stored in attributes includes:
* - The location of the key in storage, indicated by its key identifier and its lifetime.
* - The keys policy, comprising usage flags and a specification of the permitted
* algorithm(s).
* - Information about the key itself: the key type and its size.
* - Implementations can define additional attributes.
*
* The actual key material is not considered an attribute of a key. Key attributes do not
* contain information that is generally considered highly confidential.
*
* @note Implementations are recommended to define the attribute object as a simple data
* structure, with fields corresponding to the individual key attributes. In such an
* implementation, each function @c psa_set_key_xxx() sets a field and the corresponding
* function @c psa_get_key_xxx() retrieves the value of the field.
* An implementation can report attribute values that are equivalent to the original one,
* but have a different encoding. For example, an implementation can use a more compact
* representation for types where many bit-patterns are invalid or not supported, and
* store all values that it does not support as a special marker value. In such an
* implementation, after setting an invalid value, the corresponding get function returns
* an invalid value which might not be the one that was originally stored.
*
* This is an implementation-defined type. Applications that make assumptions about the
* content of this object will result in in implementation-specific behavior, and are
* non-portable.
*
* An attribute object can contain references to auxiliary resources, for example pointers
* to allocated memory or indirect references to pre-calculated values. In order to free
* such resources, the application must call @ref psa_reset_key_attributes(). As an
* exception, calling @ref psa_reset_key_attributes() on an attribute object is optional
* if the object has only been modified by the following functions since it was
* initialized or last reset with @ref psa_reset_key_attributes():
* - @ref psa_set_key_id()
* - @ref psa_set_key_lifetime()
* - @ref psa_set_key_type()
* - @ref psa_set_key_bits()
* - @ref psa_set_key_usage_flags()
* - @ref psa_set_key_algorithm()
* Before calling any function on a key attribute object, the application must initialize
* it by any of the following means:
* - Set the object to all-bits-zero, for example:
* @code
* @ref psa_key_attributes_t attributes;
* memset(&attributes, 0, sizeof(attributes));
* @endcode
* - Initialize the object to logical zero values by declaring the object as static or
* global without an explicit initializer, for example:
* @code
* static @ref psa_key_attributes_t attributes;
* @endcode
* - Initialize the object to the initializer @ref PSA_KEY_ATTRIBUTES_INIT, for example:
* @code
* @ref psa_key_attributes_t attributes = @ref PSA_KEY_ATTRIBUTES_INIT;
* @endcode
* - Assign the result of the function @ref psa_key_attributes_init() to the object,
* for example:
* @code
* @ref psa_key_attributes_t attributes;
* attributes = @ref psa_key_attributes_init();
* @endcode
*
* A freshly initialized attribute object contains the following values:
* - lifetime: @ref PSA_KEY_LIFETIME_VOLATILE.
* - key identifier: @ref PSA_KEY_ID_NULL which is not a valid key identifier.
* - type: @ref PSA_KEY_TYPE_NONE meaning that the type is unspecified.
* - key size: @c 0 meaning that the size is unspecified.
* - usage flags: @c 0 which allows no usage except exporting a public key.
* - algorithm: @ref PSA_ALG_NONE which does not allow cryptographic usage,
* but allows exporting.
*
* ## Usage
* A typical sequence to create a key is as follows:
* -# Create and initialize an attribute object.
* -# If the key is persistent, call @ref psa_set_key_id(). Also call @ref
* psa_set_key_lifetime() to place the key in a non-default location.
* -# Set the key policy with @ref psa_set_key_usage_flags() and @ref
* psa_set_key_algorithm().
* -# Set the key type with @ref psa_set_key_type(). Skip this step if copying an existing
* key with @ref psa_copy_key().
* -# When generating a random key with @ref psa_generate_key() or deriving a key with
* @ref psa_key_derivation_output_key(), set the desired key size with @ref
* psa_set_key_bits().
* -# Call a key creation function: @ref psa_import_key(), @ref psa_generate_key(),
* @ref psa_key_derivation_output_key() or @ref psa_copy_key(). This function reads the
* attribute object, creates a key with these attributes, and outputs an identifier for
* the newly created key.
* -# Optionally call @ref psa_reset_key_attributes(), now that the attribute object is no
* longer needed. Currently this call is not required as the attributes defined in this
* specification do not require additional resources beyond the object itself.
*
* A typical sequence to query a keys attributes is as follows:
* -# Call @ref psa_get_key_attributes().
* -# Call @c psa_get_key_xxx() functions to retrieve the required attribute(s).
* -# Call @ref psa_reset_key_attributes() to free any resources that can be used by the
* attribute object.
*
* Once a key has been created, it is impossible to change its attributes.
*/
typedef struct psa_key_attributes_s psa_key_attributes_t;
/**
* @brief The type of the state object for multi-part cipher operations.
*
* @details Before calling any function on a cipher operation object, the application must
* initialize it by any of the following means:
* - Set the object to all-bits-zero, for example:
* @code
* @ref psa_cipher_operation_t operation;
* memset(&operation, 0, sizeof(operation));
* @endcode
* - Initialize the object to logical zero values by declaring the object as static or
* global without an explicit initializer, for example:
* @code
* static @ref psa_cipher_operation_t operation;
* @endcode
* - Initialize the object to the initializer @ref PSA_CIPHER_OPERATION_INIT, for example:
* @code
* @ref psa_cipher_operation_t operation = @ref PSA_CIPHER_OPERATION_INIT;
* @endcode
* - Assign the result of the function @ref psa_cipher_operation_init() to the object,
* for example:
* @code
* @ref psa_cipher_operation_t operation;
* operation = @ref psa_cipher_operation_init();
* @endcode
*
* This is an implementation-defined type. Applications that make assumptions about the
* content of this object will result in in implementation-specific behavior, and are
* non-portable.
*/
typedef struct psa_cipher_operation_s psa_cipher_operation_t;
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_PSA_CRYPTO_TYPES_H */
/** @} */

File diff suppressed because it is too large Load Diff

24
sys/psa_crypto/Kconfig Normal file
View File

@ -0,0 +1,24 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_PSA_CRYPTO
bool "PSA Crypto"
depends on TEST_KCONFIG
select MODULE_RANDOM
if MODULE_PSA_CRYPTO
rsource "Kconfig.asymmetric"
rsource "Kconfig.ciphers"
rsource "Kconfig.hashes"
rsource "Kconfig.mac"
rsource "Kconfig.keys"
rsource "psa_se_mgmt/Kconfig"
rsource "psa_key_slot_mgmt/Kconfig"
endif # MODULE_PSA_CRYPTO

View File

@ -0,0 +1,61 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_PSA_ASYMMETRIC
bool "PSA Asymmetric Crypto"
select PSA_KEY_CONFIG
select MODULE_PSA_KEY_SLOT_MGMT
if MODULE_PSA_ASYMMETRIC
menuconfig MODULE_PSA_ASYMMETRIC_ECC_P192R1
bool "ECC NIST-P192R1"
select PSA_KEY_SIZE_192
if MODULE_PSA_ASYMMETRIC_ECC_P192R1
choice PSA_ASYMMETRIC_ECC_P192R1_BACKEND
bool "ECC NIST-P192R1 Implementation"
config MODULE_PSA_ASYMMETRIC_ECC_P192R1_BACKEND_PERIPH
bool "Hardware accelerated with peripheral"
depends on HAS_PERIPH_ECC_P192R1
select MODULE_PERIPH_ECC_P192R1
config MODULE_PSA_ASYMMETRIC_ECC_P192R1_BACKEND_MICROECC
bool "Micro-ECC Package"
select PACKAGE_MICRO-ECC
select MODULE_PSA_UECC_P192
endchoice
endif # MODULE_PSA_ASYMMETRIC_ECC_P192R1
menuconfig MODULE_PSA_ASYMMETRIC_ECC_P256R1
bool "ECC NIST-P256R1"
select PSA_KEY_SIZE_256
if MODULE_PSA_ASYMMETRIC_ECC_P256R1
choice PSA_ASYMMETRIC_ECC_P256R1_BACKEND
bool "ECC NIST-P256R1 Implementation"
config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_PERIPH
bool "Hardware Accelerated"
depends on HAS_PERIPH_ECC_P256R1
select MODULE_PERIPH_ECC_P256R1
config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_MICROECC
bool "Micro-ECC Package"
select PACKAGE_MICRO-ECC
select MODULE_PSA_UECC_P256
endchoice
endif # MODULE_PSA_ASYMMETRIC_ECC_P256R1
endif # MODULE_PSA_ASYMMETRIC

View File

@ -0,0 +1,92 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_PSA_CIPHER
bool "PSA Ciphers"
select PSA_KEY_CONFIG
select MODULE_PSA_KEY_SLOT_MGMT
if MODULE_PSA_CIPHER
menuconfig MODULE_PSA_CIPHER_AES_128_ECB
bool "AES-128 ECB"
select PSA_KEY_SIZE_128
if MODULE_PSA_CIPHER_AES_128_ECB
choice PSA_CIPHER_AES_128_ECB_BACKEND
bool "AES-128 Implementation"
config MODULE_PSA_CIPHER_AES_128_ECB_BACKEND_RIOT
bool "RIOT cipher"
select MODULE_CRYPTO
select MODULE_PSA_RIOT_CIPHER_AES_ECB
endchoice
endif # MODULE_PSA_CIPHER_AES_128_ECB
menuconfig MODULE_PSA_CIPHER_AES_128_CBC
bool "AES-128 CBC"
select PSA_KEY_SIZE_128
if MODULE_PSA_CIPHER_AES_128_CBC
choice PSA_CIPHER_AES_128_CBC_BACKEND
bool "AES-128 CBC Implementation"
config MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_PERIPH
bool "Hardware Accelerated"
depends on HAS_PERIPH_CIPHER_AES_128_CBC
select MODULE_PERIPH_CIPHER_AES_128_CBC
config MODULE_PSA_CIPHER_AES_128_CBC_BACKEND_RIOT
bool "RIOT cipher"
select MODULE_CRYPTO
select MODULE_PSA_RIOT_CIPHER_AES_128_CBC
endchoice
endif # MODULE_PSA_CIPHER_AES_128_CBC
menuconfig MODULE_PSA_CIPHER_AES_192_CBC
bool "AES-192 CBC"
select PSA_KEY_SIZE_192
if MODULE_PSA_CIPHER_AES_192_CBC
choice PSA_CIPHER_AES_192_CBC_BACKEND
bool "AES-192 Implementation"
config MODULE_PSA_CIPHER_AES_192_CBC_BACKEND_RIOT
bool "RIOT cipher"
select MODULE_CRYPTO
select MODULE_PSA_RIOT_CIPHER_AES_CBC
endchoice
endif # MODULE_PSA_CIPHER_AES_192_CBC
menuconfig MODULE_PSA_CIPHER_AES_256_CBC
bool "AES-256 CBC"
select PSA_KEY_SIZE_256
if MODULE_PSA_CIPHER_AES_256_CBC
choice CIPHER_AES_256_CBC_BACKEND
bool "AES-256 Implementation"
config MODULE_PSA_CIPHER_AES_256_CBC_BACKEND_RIOT
bool "RIOT Cipher Module"
select MODULE_CRYPTO
select MODULE_PSA_RIOT_CIPHER_AES_CBC
endchoice
endif # MODULE_PSA_CIPHER_AES_256_CBC
endif # MODULE_PSA_CIPHER

View File

@ -0,0 +1,111 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_PSA_HASH
bool "PSA Hashes"
select PSA_KEY_CONFIG
if MODULE_PSA_HASH
menuconfig MODULE_PSA_HASH_MD5
bool "MD5"
if MODULE_PSA_HASH_MD5
choice PSA_HASH_MD5_BACKEND
bool "MD5 implementation"
config MODULE_PSA_HASH_MD5_BACKEND_RIOT
bool "RIOT hash"
select MODULE_PSA_RIOT_HASHES_MD5
endchoice
endif # MODULE_PSA_HASH_MD5
menuconfig MODULE_PSA_HASH_SHA_1
bool "SHA-1"
if MODULE_PSA_HASH_SHA_1
choice PSA_HASH_SHA_1_BACKEND
bool "SHA-1 implementation"
config MODULE_PSA_HASH_SHA_1_BACKEND_PERIPH
bool "Hardware accelerated"
depends on HAS_PERIPH_HASH_SHA_1
select MODULE_PERIPH_HASH_SHA_1
config MODULE_PSA_HASH_SHA_1_BACKEND_RIOT
bool "RIOT hash"
select MODULE_PSA_RIOT_HASHES_SHA_1
endchoice
endif # MODULE_PSA_HASH_SHA_1
menuconfig MODULE_PSA_HASH_SHA_224
bool "SHA-224"
if MODULE_PSA_HASH_SHA_224
choice PSA_HASH_SHA_224_BACKEND
bool "SHA-224 implementation"
config MODULE_PSA_HASH_SHA_224_BACKEND_PERIPH
bool "Hardware accelerated"
depends on HAS_PERIPH_HASH_SHA_224
select MODULE_PERIPH_HASH_SHA_224
config MODULE_PSA_HASH_SHA_224_BACKEND_RIOT
bool "RIOT Hash Module"
select MODULE_PSA_RIOT_HASHES_SHA_224
endchoice
endif # MODULE_PSA_HASH_SHA_224
menuconfig MODULE_PSA_HASH_SHA_256
bool "SHA-256"
if MODULE_PSA_HASH_SHA_256
choice PSA_HASH_SHA_256_BACKEND
bool "SHA-256 implementation"
config MODULE_PSA_HASH_SHA_256_BACKEND_PERIPH
bool "Hardware accelerated"
depends on HAS_PERIPH_HASH_SHA_256
select MODULE_PERIPH_HASH_SHA_256
config MODULE_PSA_HASH_SHA_256_BACKEND_RIOT
bool "RIOT hash"
select MODULE_PSA_RIOT_HASHES_SHA_256
endchoice
endif # MODULE_PSA_HASH_SHA_256
menuconfig MODULE_PSA_HASH_SHA_512
bool "SHA-512"
depends on HAS_PERIPH_HASH_SHA_512 # no software implementation so far...
if MODULE_PSA_HASH_SHA_512
choice PSA_HASH_SHA_512_BACKEND
bool "SHA-512 implementation"
config MODULE_PSA_HASH_SHA_512_BACKEND_PERIPH
bool "Hardware accelerated"
depends on HAS_PERIPH_HASH_SHA_512
select MODULE_PERIPH_HASH_SHA_512
endchoice
endif # MODULE_PSA_HASH_SHA_512
endif # MODULE_PSA_HASH

View File

@ -0,0 +1,55 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menu "PSA Key Management Configuration"
config PSA_KEY_SIZE_128
bool "Application uses key of size 128 Bits"
help
Indicates that the maximum PSA key size should be at least 128 bits.
config PSA_KEY_SIZE_192
bool
help
Indicates that the maximum PSA key size should be at least 192 bits.
config PSA_KEY_SIZE_256
bool
help
Indicates that the maximum PSA key size should be at least 256 bits.
config PSA_KEY_SIZE_512
bool
help
Indicates that the maximum PSA key size should be at least 512 bits.
config PSA_MAX_KEY_SIZE
int
default 64 if PSA_KEY_SIZE_512
default 32 if PSA_KEY_SIZE_256
default 24 if PSA_KEY_SIZE_192
default 16 if PSA_KEY_SIZE_128
default 0
help
Indicates the maximum PSA key size in bytes.
config PSA_PROTECTED_KEY_COUNT
int "Specifies number of allocated protected key slots"
default 5 if MODULE_PSA_SECURE_ELEMENT
default 0
config PSA_ASYMMETRIC_KEYPAIR_COUNT
int "Specifies number of allocated key pair slots"
default 5 if MODULE_PSA_ASYMMETRIC
default 0
config PSA_SINGLE_KEY_COUNT
int "Specifies number of allocated single key slots"
default 5 if PSA_MAX_KEY_SIZE != 0
default 0
endmenu # PSA Key Management Configuration

View File

@ -0,0 +1,37 @@
# Copyright (c) 2022 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_PSA_MAC
bool "PSA Message Authenticated Ciphers"
select PSA_KEY_CONFIG
select MODULE_PSA_KEY_SLOT_MGMT
if MODULE_PSA_MAC
menuconfig MODULE_PSA_MAC_HMAC_SHA_256
bool "HMAC SHA-256"
select PSA_KEY_SIZE_256
if MODULE_PSA_MAC_HMAC_SHA_256
choice PSA_MAC_HMAC_SHA_256_BACKEND
bool "HMAC SHA256 Implementation"
config MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_PERIPH
bool "Hardware Accelerated"
depends on HAS_PERIPH_HMAC_SHA_256
select MODULE_PERIPH_HMAC_SHA_256
config MODULE_PSA_MAC_HMAC_SHA_256_BACKEND_RIOT
bool "RIOT HMAC SHA-256"
select MODULE_PSA_RIOT_HASHES_HMAC_SHA256
endchoice # PSA_MAC_HMAC_SHA_256_BACKEND
endif # MODULE_PSA_MAC_HMAC_SHA_256
endif # MODULE_PSA_MAC

15
sys/psa_crypto/Makefile Normal file
View File

@ -0,0 +1,15 @@
# PSA Crypto casts like hell, so this needs to shut the f up
CFLAGS += -Wno-cast-align
# include the PSA headers
INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
ifneq (,$(filter psa_key_slot_mgmt,$(USEMODULE)))
DIRS += psa_key_slot_mgmt
endif
ifneq (,$(filter psa_se_mgmt,$(USEMODULE)))
DIRS += psa_se_mgmt
endif
include $(RIOTBASE)/Makefile.base

241
sys/psa_crypto/Makefile.dep Normal file
View File

@ -0,0 +1,241 @@
ifneq (,$(filter psa_crypto,$(USEMODULE)))
USEMODULE += random
USEMODULE += prng_musl_lcg
endif
# Asymmetric
ifneq (,$(filter psa_asymmetric,$(USEMODULE)))
USEMODULE += psa_key_slot_mgmt
endif
## ECC_P192R1 backend
ifneq (,$(filter psa_asymmetric_ecc_p192r1,$(USEMODULE)))
ifeq (,$(filter psa_asymmetric_ecc_p192r1_custom_backend,$(USEMODULE)))
FEATURES_OPTIONAL += periph_ecc_p192r1
include $(RIOTMAKE)/features_check.inc.mk
# HACK: Due to kconfig migration, may cause problems
ifneq (,$(filter periph_ecc_p192r1,$(FEATURES_USED)))
USEMODULE += psa_asymmetric_ecc_p192r1_backend_periph
else
USEMODULE += psa_asymmetric_ecc_p192r1_backend_microecc
endif
endif
endif
ifneq (,$(filter psa_asymmetric_ecc_p192r1_backend_microecc, $(USEMODULE)))
USEPKG += micro-ecc
USEMODULE += psa_uecc
USEMODULE += psa_uecc_p192
endif
ifneq (,$(filter psa_asymmetric_ecc_p192r1_backend_periph,$(USEMODULE)))
FEATURES_REQUIRED += periph_ecc_p192r1
endif
## ECC_P256R1 backend
ifneq (,$(filter psa_asymmetric_ecc_p256r1,$(USEMODULE)))
ifeq (,$(filter psa_asymmetric_ecc_p256r1_custom_backend,$(USEMODULE)))
FEATURES_OPTIONAL += periph_ecc_p256r1
include $(RIOTMAKE)/features_check.inc.mk
# HACK: Due to kconfig migration, may cause problems
ifneq (,$(filter periph_ecc_p256r1,$(FEATURES_USED)))
USEMODULE += psa_asymmetric_ecc_p256r1_backend_periph
else
USEMODULE += psa_asymmetric_ecc_p256r1_backend_microecc
endif
endif
endif
ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_microecc,$(USEMODULE)))
USEPKG += micro-ecc
USEMODULE += psa_uecc
USEMODULE += psa_uecc_p256
endif
ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_periph,$(USEMODULE)))
FEATURES_REQUIRED += periph_ecc_p256r1
endif
# Cipher
ifneq (,$(filter psa_cipher,$(USEMODULE)))
USEMODULE += psa_key_slot_mgmt
endif
## AES-128-ECB backend
ifneq (,$(filter psa_cipher_aes_128_ecb,$(USEMODULE)))
USEMODULE += psa_cipher_aes_128_ecb_backend_riot
endif
ifneq (,$(filter psa_cipher_aes_128_ecb_backend_riot,$(USEMODULE)))
USEMODULE += crypto
USEMODULE += cipher_modes
USEMODULE += psa_riot_cipher
USEMODULE += psa_riot_cipher_aes_ecb
endif
## AES-128-CBC
ifneq (,$(filter psa_cipher_aes_128_cbc,$(USEMODULE)))
ifeq (,$(filter psa_cipher_aes_128_cbc_custom_backend,$(USEMODULE)))
FEATURES_OPTIONAL += periph_cipher_aes_128_cbc
include $(RIOTMAKE)/features_check.inc.mk
# HACK: Due to kconfig migration, may cause problems
ifneq (,$(filter periph_cipher_aes_128_cbc,$(FEATURES_USED)))
USEMODULE += psa_cipher_aes_128_cbc_backend_periph
else
USEMODULE += psa_cipher_aes_128_cbc_backend_riot
endif
endif
endif
ifneq (,$(filter psa_cipher_aes_128_cbc_backend_periph,$(USEMODULE)))
FEATURES_REQUIRED += periph_cipher_aes_128_cbc
endif
ifneq (,$(filter psa_cipher_aes_128_cbc_backend_riot,$(USEMODULE)))
USEMODULE += crypto
USEMODULE += cipher_modes
USEMODULE += psa_riot_cipher
USEMODULE += psa_riot_cipher_aes_128_cbc
endif
## AES-192-CBC
ifneq (,$(filter psa_cipher_aes_192_cbc,$(USEMODULE)))
USEMODULE += psa_cipher_aes_192_cbc_backend_riot
endif
ifneq (,$(filter psa_cipher_aes_192_cbc_backend_riot,$(USEMODULE)))
USEMODULE += crypto
USEMODULE += cipher_modes
USEMODULE += psa_riot_cipher
USEMODULE += psa_riot_cipher_aes_192_cbc
endif
# Hash
## MD5
ifneq (,$(filter psa_hash_md5,$(USEMODULE)))
USEMODULE += psa_hash_md5_backend_riot
endif
ifneq (,$(filter psa_hash_md5_backend_riot,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += psa_riot_hashes
USEMODULE += psa_riot_hashes_md5
endif
## SHA-1
ifneq (,$(filter psa_hash_sha_1,$(USEMODULE)))
ifeq (,$(filter psa_hash_sha_1_custom_backend,$(USEMODULE)))
FEATURES_OPTIONAL += periph_hash_sha_1
include $(RIOTMAKE)/features_check.inc.mk
# HACK: Due to kconfig migration, may cause problems
ifneq (,$(filter periph_hash_sha_1,$(FEATURES_USED)))
USEMODULE += psa_hash_sha_1_backend_periph
else
USEMODULE += psa_hash_sha_1_backend_riot
endif
endif
endif
ifneq (,$(filter psa_hash_sha_1_backend_periph,$(USEMODULE)))
FEATURES_REQUIRED += periph_hash_sha_1
endif
ifneq (,$(filter psa_hash_sha_1_backend_riot,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += psa_riot_hashes
USEMODULE += psa_riot_hashes_sha_1
endif
## SHA-224
ifneq (,$(filter psa_hash_sha_224,$(USEMODULE)))
ifeq (,$(filter psa_hash_sha_224_custom_backend,$(USEMODULE)))
FEATURES_OPTIONAL += periph_hash_sha_224
include $(RIOTMAKE)/features_check.inc.mk
# HACK: Due to kconfig migration, may cause problems
ifneq (,$(filter periph_hash_sha_224,$(FEATURES_USED)))
USEMODULE += psa_hash_sha_224_backend_periph
else
USEMODULE += psa_hash_sha_224_backend_riot
endif
endif
endif
ifneq (,$(filter psa_hash_sha_224_backend_periph,$(USEMODULE)))
FEATURES_REQUIRED += periph_hash_sha_224
endif
ifneq (,$(filter psa_hash_sha_224_backend_riot,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += psa_riot_hashes
USEMODULE += psa_riot_hashes_sha_224
endif
## SHA-256
ifneq (,$(filter psa_hash_sha_256,$(USEMODULE)))
ifeq (,$(filter psa_hash_sha_256_custom_backend,$(USEMODULE)))
FEATURES_OPTIONAL += periph_hash_sha_256
include $(RIOTMAKE)/features_check.inc.mk
# HACK: Due to kconfig migration, may cause problems
ifneq (,$(filter periph_hash_sha_256,$(FEATURES_USED)))
USEMODULE += psa_hash_sha_256_backend_periph
else
USEMODULE += psa_hash_sha_256_backend_riot
endif
endif
endif
ifneq (,$(filter psa_hash_sha_256_backend_periph,$(USEMODULE)))
FEATURES_REQUIRED += periph_hash_sha_256
endif
ifneq (,$(filter psa_hash_sha_256_backend_riot,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += psa_riot_hashes
USEMODULE += psa_riot_hashes_sha_256
endif
## SHA-512
ifneq (,$(filter psa_hash_sha_512,$(USEMODULE)))
USEMODULE += psa_hash_sha_512_backend_periph
endif
ifneq (,$(filter psa_hash_sha_512_backend_periph,$(USEMODULE)))
FEATURES_REQUIRED += periph_hash_sha_512
endif
# MAC
## HMAC SHA-256
ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE)))
ifeq (,$(filter psa_mac_hmac_sha_256_custom_backend,$(USEMODULE)))
FEATURES_OPTIONAL += periph_hmac_sha_256
include $(RIOTMAKE)/features_check.inc.mk
# HACK: Due to kconfig migration, may cause problems
ifneq (,$(filter periph_hmac_sha_256,$(FEATURES_USED)))
USEMODULE += psa_mac_hmac_sha_256_backend_periph
else
USEMODULE += psa_mac_hmac_sha_256_backend_riot
endif
endif
endif
ifneq (,$(filter psa_mac_hmac_sha_256_backend_periph,$(USEMODULE)))
FEATURES_REQUIRED += periph_hmac_sha_256
endif
ifneq (,$(filter psa_mac_hmac_sha_256_backend_riot,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += psa_riot_hashes
USEMODULE += psa_riot_hashes_hmac_sha256
endif
# Secure Elements
ifneq (,$(filter psa_secure_element,$(USEMODULE)))
USEMODULE += psa_se_mgmt
USEMODULE += psa_key_slot_mgmt
endif
ifneq (,$(filter psa_secure_element_ateccx08a, $(USEMODULE)))
USEPKG += cryptoauthlib
USEMODULE += psa_secure_element_config
endif

View File

@ -0,0 +1,154 @@
# include the PSA headers
INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
# Workaround for mbedtls namespacing issue
# sys/include will include the conflicting header files in psa but requires a psa/*.h structure.
INCLUDES += -I$(RIOTBASE)/sys/include/psa_crypto
backends = $(words $(filter $1_backend_%,$(USEMODULE)))
# Pseudomodules
## Asymmetric
PSEUDOMODULES += psa_asymmetric
PSEUDOMODULES += psa_asymmetric_ecc_p192r1
PSEUDOMODULES += psa_asymmetric_ecc_p192r1_backend_microecc
PSEUDOMODULES += psa_asymmetric_ecc_p192r1_backend_periph
PSEUDOMODULES += psa_asymmetric_ecc_p192r1_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_asymmetric_ecc_p192r1,$(USEMODULE)))
ifneq (1,$(call backends, psa_asymmetric_ecc_p192r1))
$(error "One (and only one) backend should be selected for psa_asymmetric_ecc_p192r1")
endif
endif
PSEUDOMODULES += psa_asymmetric_ecc_p256r1
PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_microecc
PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_periph
PSEUDOMODULES += psa_asymmetric_ecc_p256r1_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_asymmetric_ecc_p256r1,$(USEMODULE)))
ifneq (1,$(call backends,psa_asymmetric_ecc_p256r1))
$(error "One (and only one) backend should be selected for psa_asymmetric_ecc_p256r1")
endif
endif
## Cipher
PSEUDOMODULES += psa_cipher
PSEUDOMODULES += psa_cipher_aes_128_ecb
PSEUDOMODULES += psa_cipher_aes_128_ecb_backend_riot
PSEUDOMODULES += psa_cipher_aes_128_cbc
PSEUDOMODULES += psa_cipher_aes_128_cbc_backend_periph
PSEUDOMODULES += psa_cipher_aes_128_cbc_backend_riot
PSEUDOMODULES += psa_cipher_aes_128_cbc_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_cipher_aes_128_cbc,$(USEMODULE)))
ifneq (1,$(call backends,psa_cipher_aes_128_cbc))
$(error "One (and only one) backend should be selected for psa_cipher_aes_128_cbc")
endif
endif
PSEUDOMODULES += psa_cipher_aes_192_cbc
PSEUDOMODULES += psa_cipher_aes_192_cbc_backend_riot
PSEUDOMODULES += psa_cipher_aes_192_cbc_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_cipher_aes_192_cbc,$(USEMODULE)))
ifneq (1,$(call backends,psa_cipher_aes_192_cbc))
$(error "One (and only one) backend should be selected for psa_cipher_aes_192_cbc")
endif
endif
PSEUDOMODULES += psa_cipher_aes_256_cbc
PSEUDOMODULES += psa_cipher_aes_256_cbc_backend_riot
PSEUDOMODULES += psa_cipher_aes_256_cbc_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_cipher_aes_256_cbc,$(USEMODULE)))
ifneq (1,$(call backends,psa_cipher_aes_256_cbc))
$(error "One (and only one) backend should be selected for psa_cipher_aes_256_cbc")
endif
endif
## Hash
PSEUDOMODULES += psa_hash
PSEUDOMODULES += psa_hash_md5
PSEUDOMODULES += psa_hash_md5_backend_riot
PSEUDOMODULES += psa_hash_md5_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_hash_md5,$(USEMODULE)))
ifneq (1,$(call backends,psa_hash_md5))
$(error "One (and only one) backend should be selected for psa_hash_md5")
endif
endif
PSEUDOMODULES += psa_hash_sha_1
PSEUDOMODULES += psa_hash_sha_1_backend_periph
PSEUDOMODULES += psa_hash_sha_1_backend_riot
PSEUDOMODULES += psa_hash_sha_1_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_hash_sha_1,$(USEMODULE)))
ifneq (1,$(call backends,psa_hash_sha_1))
$(error "One (and only one) backend should be selected for psa_hash_sha_1")
endif
endif
PSEUDOMODULES += psa_hash_sha_224
PSEUDOMODULES += psa_hash_sha_224_backend_periph
PSEUDOMODULES += psa_hash_sha_224_backend_riot
PSEUDOMODULES += psa_hash_sha_224_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_hash_sha_224,$(USEMODULE)))
ifneq (1,$(call backends,psa_hash_sha_224))
$(error "One (and only one) backend should be selected for psa_hash_sha_224")
endif
endif
PSEUDOMODULES += psa_hash_sha_256
PSEUDOMODULES += psa_hash_sha_256_backend_periph
PSEUDOMODULES += psa_hash_sha_256_backend_riot
PSEUDOMODULES += psa_hash_sha_256_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_hash_sha_256,$(USEMODULE)))
ifneq (1,$(call backends,psa_hash_sha_256))
$(error "One (and only one) backend should be selected for psa_hash_sha_256")
endif
endif
PSEUDOMODULES += psa_hash_sha_512
PSEUDOMODULES += psa_hash_sha_512_backend_periph
PSEUDOMODULES += psa_hash_sha_512_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_hash_sha_512,$(USEMODULE)))
ifneq (1,$(call backends,psa_hash_sha_512))
$(error "One (and only one) backend should be selected for psa_hash_sha_512")
endif
endif
## MAC
PSEUDOMODULES += psa_mac
PSEUDOMODULES += psa_mac_hmac_sha_256
PSEUDOMODULES += psa_mac_hmac_sha_256_backend_periph
PSEUDOMODULES += psa_mac_hmac_sha_256_backend_riot
PSEUDOMODULES += psa_mac_hmac_sha_256_custom_backend
# check that one and only one backend has been selected
ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE)))
ifneq (1,$(call backends,psa_mac_hmac_sha_256))
$(error "One (and only one) backend should be selected for psa_mac_hmac_sha_256")
endif
endif
## Secure Elements
PSEUDOMODULES += psa_secure_element
PSEUDOMODULES += psa_secure_element_asymmetric
PSEUDOMODULES += psa_secure_element_config
PSEUDOMODULES += psa_secure_element_multiple

996
sys/psa_crypto/doc.txt Normal file
View File

@ -0,0 +1,996 @@
/**
* @defgroup sys_psa_crypto PSA Cryptographic API
* @ingroup sys
* @brief Implements the PSA Crypto API specification.
* @see https://armmbed.github.io/mbed-crypto/html/
*
* @warning This implementation is not complete and not yet thoroughly tested.
* Please do not use this module in production, as it may introduce security issues.
*
* @note This implementation is not complete and will be successively expanded.
*
* About {#About}
* =====
* This module implements the PSA Cryptography API Version 1.1 as specified
* [here](https://armmbed.github.io/mbed-crypto/html/).
* It provides an OS level access to cryptographic operations and supports software and hardware
* backends as well as the use of secure elements.
* The API automatically builds a hardware backend for an operation, if there's one available,
* otherwise it falls back to software. Specific backends can be configured, if needed.
* For configuration options see [Configuration](#configuration).
*
* PSA Crypto has an integrated key management module, which stores keys internally
* without exposing them to applications. To learn how to use keys with PSA,
* read [Using Keys](#using-keys).
*
* A basic usage and configuration example can be found in `examples/psa_crypto`.
* For more usage instructions, please read the documentation.
*
* If you want to add your own crypto backend, see [Porting Guide](#porting-guide).
*
* Basic Usage
* ===
* To use PSA Crypto, add `psa/crypto.h` to your includes. This will make all
* operations and macros available.
*
* Call `psa_crypto_init()` before calling any other operation.
*
* ## Structure Initialization
* Whenever you declare a PSA Crypto structure (e.g. operation contexts or key attributes),
* it needs to be initialized with zeroes. A structure that is not initialized will be interpreted
* by PSA as *active* and can not be used for a new operation.
* The example function and macro shown below result in the same thing: A new, inactive structure.
*
* @code {.c}
* // Choose one of these options
* psa_hash_operation_t hash_op = psa_hash_operation_init();
* psa_hash_operation_t hash_op = PSA_HASH_OPERATION_INIT;
* @endcode
*
* An already active operation can be set to zero by reinitializing it. It then becomes *inactive*
* again and can be used for a new operation.
*
* When errors occur during execution, PSA resets the operation contexts and makes them
* *inactive*, to prevent unauthorized access to an operation's state.
* Users can also call `psa_<operation>_abort()` anytime in between function calls to do the same.
*
* Using Keys {#using-keys}
* ===
* PSA can only operate on keys, that are registered with and stored within the internal
* key storage module. This means you need to either generate keys with PSA or
* import an existing key.
* For this purpose there are a number of
* [key management functions](https://armmbed.github.io/mbed-crypto/html/api/keys/management.html)
* (external link).
*
* ## Key Attributes
* When creating a key for PSA, the implementation needs to know what kind of key it is
* dealing with, what it can be used for, where it's supposed to be stored, etc.
* That information needs to be specified in a set of
* [Key Attributes](https://armmbed.github.io/mbed-crypto/html/api/keys/attributes.html)
* (external link).
*
* The example below defines attributes for an AES-128 key, which can be used for CBC encryption
* and decryption and will be stored in local volatile memory.
* @code
* // Initializes empty attributes structure
* psa_key_attributes_t attributes = psa_key_attributes_init();
*
* // Set all necessary attributes
* psa_set_key_lifetime(&attributes, PSA_KEY_LIFETIME_VOLATILE);
* psa_set_key_type(&attributes, PSA_KEY_TYPE_AES);
* psa_set_key_bits(&attributes, 128);
* psa_set_key_algorithm(&attributes, PSA_ALG_CBC_NO_PADDING);
* psa_set_key_usage_flags(&attributes, (PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT));
* @endcode
*
* After setting the attributes, an exiting key can be imported:
* @code
* uint8_t aes_key[] = { ... };
* psa_key_id_t key_id = 0; // Will be set by PSA Crypto
* psa_status_t status = psa_import_key(&attributes, aes_key, sizeof(aes_key), &key_id);
* @endcode
* The PSA Crypto implementation will assign an identifier to the key and return it
* via the `key_id` parameter. This identifier can then be used for operations with this
* specific key.
* @code
* uint8_t PLAINTEXT[] = { ... };
* // Buffer sizes can be calculated with macros
* size_t output_buf_size = PSA_CIPHER_ENCRYPT_OUTPUT_SIZE(PSA_KEY_TYPE_AES, PSA_ALG_CBC_NO_PADDING,sizeof(PLAINTEXT));
* uint8_t output_buffer[output_buf_size];
*
* status = psa_cipher_encrypt(key_id, PSA_ALG_CBC_NO_PADDING, PLAINTEXT, sizeof(PLAINTEXT),output_buffer, sizeof(output_buffer), &output_length));
* @endcode
*
* All the supported key types, algorithms and usage flags can be found in the documentation.
*
* ### Key Lifetime {#key-lifetime}
* #### Volatile vs. Persistent
* The PSA API specifies two ways of storing keys: volatile and persistent. Volatile
* keys will be stored only in RAM, which means they will be destroyed after application
* termination or a device reset.
* Persistent keys will also be written into flash memory for later access. To destroy
* them they must be explicitly deleted with the `psa_destroy_key()` function.
*
* @note So far this implementation only supports volatile storage. Persistent storage
* will be added in the future.
*
* #### Lifetime Encoding
* When creating a key, the user needs to specify a lifetime value, which actually consists
* of two values: persistence and location. The location defines the actual memory location
* of the key (e.g. whether the key will be stored in RAM, in a hardware protected memory slot
* or on an external device like a secure element).
*
* The persistence value defines whether the key will be stored in RAM (volatile)
* in flash (persistent).
* Some default values that exist are:
* - @ref PSA_KEY_LIFETIME_VOLATILE (stored in local, volatile memory)
* - @ref PSA_KEY_LIFETIME_PERSISTENT (stored in local, persistent memory)
*
* Other lifetime values can be constructed with the macro
* `PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION(persistence, location)`.
* All supported `PSA_KEY_PERSISTENCE_*` and `PSA_KEY_LOCATION_*` values can be combined.
*
* In addition to the location values defined by the specification, this implementation also
* supports values for [Secure Elements](#secure-elements).
*
* Configuration {#configuration}
* ===
* Currently there are two ways to configure PSA Crypto: Kconfig and Makefiles. An example for both
* can be found in `RIOT/examples/psa_crypto`.
*
* ## Kconfig
* We recommend using Kconfig and choosing your features in `menuconfig`.
* You can access the GUI by calling
*
* @code
* TEST_KCONFIG=1 BOARD=<your board> make menuconfig
* @endcode
*
* from your application directory.
* There you can find the available PSA features and options under `System->PSA Crypto`.
* If you only select the operations you want to use (e.g. `PSA Ciphers->AES-128 CBC`), Kconfig
* will automatically select the best backend for you depending on the board (e.g. a hardware
* accelerator if it is available). Optionally you can force a custom backend.
*
* Further you can specify the exact number of keys you need to store (section `PSA Key Management
* Configuration` in `menuconfig`), or choose your [Secure Element](#secure-elements)
* configurations.
*
* Alternatively you can create an `app.config.test` file in your application folder
* and choose your symbols there (see `examples/psa_crypto`).
*
* In the `app.config.test` file, modules can be chosen with the following syntax:
* `CONFIG_MODULE_<MODULENAME>=y`, as shown below.
* @code
* CONFIG_MODULE_PSA_CRYPTO=y
* CONFIG_MODULE_PSA_CIPHER=y
* CONFIG_MODULE_PSA_CIPHER_AES_128_CBC=y
* @endcode
*
* ## Makefiles
* If you don't want to use Kconfig, you can use the traditional way in RIOT of selecting
* modules in your application Makefile.
*
* Here you need to set the base module and individual modules for each operation you need.
* The example below also chooses a default backend depending on your board.
* @code
* // Base module: this is required!
* USEMODULE += psa_crypto
*
* USEMODULE += psa_cipher
* USEMODULE += psa_cipher_aes_128_cbc
* @endcode
*
* If desired, you can choose a specific backend at compile time. For this you need to specify
* that you want to set a custom backend and then explicitly choose the one you want (see below).
* @code
* USEMODULE += psa_cipher_aes_128_cbc_custom_backend
* USEMODULE += psa_cipher_aes_128_cbc_backend_riot
* @endcode
*
* The currently available modules, are listed [below](#available-modules).
*
* ## Key Slot Types {#configuration-keys}
* The key management of PSA keeps track of keys by storing them in virtual key slot
* representations, along with their attributes. Since keys can come in various sizes,
* it would be inefficient to allocate the same amount of memory for all keys.
* To reduce the amount of memory used for key storage, PSA internally differentiates between
* three types of key slots (see below). Depending on the operations your application uses, PSA will
* automatically detect the key sizes needed and will allocate the required memory.
* The number of key slots allocated of each type is set to five per default, but can be changed by
* the user depending on their requirements.
*
* | Single Key Slot | Asymmetric Key Slot | Protected Key Slot |
* |----------------|---------------------|--------------------|
* | Single keys or unstructured data,<br>e.g. AES keys or asymmetric<br>public keys in local memory | Asymmetric key pairs<br>(private and public parts) <br>in local memory | Any keys stored on a secure<br>element or on-chip in<br>hardware protected memory |
*
* If you want to change the default number of allocated key slots you can do so by
* updating the number in `menuconfig`, or adding them to the `app.config.test` file like so:
* @code
* CONFIG_PSA_SINGLE_KEY_COUNT=3
* CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
* CONFIG_PSA_PROTECTED_KEY_COUNT=2
* @endcode
*
* When using Makefiles, you can pass CFLAGS as shown below.
* @code
* CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=3
* CFLAGS += -DCONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT=1
* CFLAGS += -DCONFIG_PSA_PROTECTED_KEY_COUNT=2
* @endcode
*
* ## Available Modules {#available-modules}
* Below are the currently available modules.
* No matter which operation you need, you always have to choose the base module.
* If you want to specify a backend other than the default, you need to select
* `psa_<operation>_custom_backend` in addition to the actual backend module.
*
* The names listed are are the version used in makefiles with the
* `USEMODULE += <modulename>` syntax.
* In Kconfig you don't need to know the exact names, you can simply choose the features in
* `menuconfig`.
* When using `app.config.test` files in your application directory, you need to write the
* names in uppercase and add the prefix `CONFIG_MODULE_` to all of them.
*
* ### Asymmetric Crypto
* - Base: psa_asymmetric
*
* #### NIST ECC P192
* - psa_asymmetric_ecc_p192r1
* - psa_asymmetric_ecc_p192r1_backend_periph
* - psa_asymmetric_ecc_p192r1_custom_backend
* - psa_asymmetric_ecc_p192r1_backend_microecc
*
* #### NIST ECC P192
* - psa_asymmetric_ecc_p256r1
* - psa_asymmetric_ecc_p256r1_backend_periph
* - psa_asymmetric_ecc_p256r1_custom_backend
* - psa_asymmetric_ecc_p256r1_backend_microecc
*
* ### Ciphers
* - Base: psa_cipher
*
* #### AES ECB
* - psa_cipher_aes_128_ecb
* - psa_cipher_aes_128_ecb_backend_riot
*
* #### AES CBC
* - psa_cipher_aes_128_cbc
* - psa_cipher_aes_128_cbc_backend_periph
* - psa_cipher_aes_128_cbc_custom_backend
* - psa_cipher_aes_128_cbc_backend_riot
* - psa_cipher_aes_192_cbc
* - psa_cipher_aes_192_cbc_custom_backend
* - psa_cipher_aes_192_cbc_backend_riot
* - psa_cipher_aes_256_cbc
* - psa_cipher_aes_256_cbc_custom_backend
* - psa_cipher_aes_256_cbc_backend_riot
*
* ### Hashes
* - Base: psa_hash
*
* #### MD5
* - psa_hash_md5
* - psa_hash_md5_custom_backend
* - psa_hash_md5_backend_riot
*
* #### SHA 1
* - psa_hash_sha_1
* - psa_hash_sha_1_backend_periph
* - psa_hash_sha_1_custom_backend
* - psa_hash_sha_1_backend_riot
*
* #### SHA 224
* - psa_hash_sha_224
* - psa_hash_sha_224_backend_periph
* - psa_hash_sha_224_custom_backend
* - psa_hash_sha_224_backend_riot
*
* #### SHA 256
* - psa_hash_sha_256
* - psa_hash_sha_256_backend_periph
* - psa_hash_sha_256_custom_backend
* - psa_hash_sha_256_backend_riot
*
* #### SHA 512
* - psa_hash_sha_512
* - psa_hash_sha_512_backend_periph
* - psa_hash_sha_512_custom_backend
*
* ### MAC
* - Base: psa_mac
*
* #### HMAC SHA 256
* - psa_mac_hmac_sha_256
* - psa_mac_hmac_sha_256_backend_periph
* - psa_mac_hmac_sha_256_custom_backend
* - psa_mac_hmac_sha_256_backend_riot
*
* ### Secure Elements
* Base:
*
* - psa_secure_element
* - psa_secure_element_multiple
*
* #### SE Types
* - psa_secure_element_ateccx08a
* - psa_secure_element_ateccx08a_ecc_p256
*
* Random Number Generation {#rng}
* ===
* Currently uses the [RIOT Random Module](#sys_random) as a backend.
* See the documentation for configuration options.
*
* Secure Elements {#secure-elements}
* ===
*
* An example showing the use of SEs can be found in `examples/psa_crypto`.
*
* To use secure elements, you first need to assign a static location value to each device,
* so PSA can find it. If you only use one device, you can use
* `PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT`. For additional devices this value must be within
* the range of `PSA_KEY_LOCATION_SE_MIN` and `PSA_KEY_LOCATION_SE_MAX`.
* When booting the system, the `auto_init` module in RIOT will automatically register the device
* with the location with PSA Crypto.
*
* You can now import or create keys on the secure element by constructing a key lifetime containing
* a device's location value.
*
* @code {.c}
* psa_key_lifetime_t lifetime =
* PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION (PSA_KEY_LIFETIME_VOLATILE,
PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT);
* @endcode
*
* Some secure elements come with their own key management and device configurations. In this case
* the configuration parameters must be passed to PSA Crypto during the registration. For this, you
* need to define a `psa_se_config_t` structure containing the configuration.
* PSA Crypto will use this structure to keep track of what types of keys are allowed on the device
* and how much storage is available.
* Where this structure should be placed, how it looks and what parameters are required depends
* on the type of your device.
*
* A good place to define that structure and the location values is a drivers `<driver>_params.h`
* file, but this may vary depending on how your device is integrated in RIOT.
*
* For detailed, device specific information, please check the device driver documentation or
* the example.
*
* ## Available Devices and Drivers
* - ATECCX08A: [Microchip Cryptoauthlib as a PSA backend](#psa-cryptoauthlib)
*
* ## Main SE Configuration
* To use SEs, the appropriate modules must be chosen in Kconfig:
* @code
* CONFIG_PSA_SECURE_ELEMENT=y
* CONFIG_PSA_SECURE_ELEMENT_ATECCX08A=y // device example
* CONFIG_PSA_SECURE_ELEMENT_ATECCX08A_ECC=y
* @endcode
*
* or added to the the Makefile:
* @code
* USEMODULE += psa_secure_element
* USEMODULE += psa_secure_element_ateccx08a // device example
* USEMODULE += psa_secure_element_ateccx08a_ecc_p256
* @endcode
*
* This implementation supports the use of one or more secure elements (SE) as backends. In this
* case the number of used secure elements must be specified (must be at least 2 and at most 255).
* When using more than one SE, add
* @code
* CONFIG_PSA_SECURE_ELEMENT_MULTIPLE=y
* CONFIG_PSA_MAX_SE_COUNT=2 // or any other number between 2 and 255
* @endcode
*
* or, respectively,
*
* @code
* USEMODULE += psa_secure_element_multiple
* CFLAGS += -DCONFIG_PSA_MAX_SE_COUNT=2 // or any other number between 2 and 255
* @endcode
*
* Porting Guide {#porting-guide}
* ===
* This porting guide focuses on how to add your software library or hardware driver
* as a backend to PSA Crypto without actually touching the PSA implementation.
* We will provide some [general information](#porting-general) and then some case
* examples for different kinds of backends:
* - [Software Libraries](#porting-software)
* - [Hardware Drivers](#porting-hardware)
* - [Secure Elements](#porting-secure-elements)
*
* Some examples to look at are:
* - [RIOT hash module](#sys_hashes)
* - [RIOT cipher module](#sys_crypto)
* - [Micro-ECC](#pkg_micro_ecc)
* - [CryptoCell 310 driver](#pkg_driver_cryptocell_310).
*
* An example integrating a secure element can be found in the
* [Cryptoauthlib Package](#pkg_cryptoauthlib).
*
* ## General Information {#porting-general}
* ### Error Values
* You should always check the status of your function calls and translate your library's or
* driver's errors to PSA error values (please be as thorough as possible).
* The PSA Crypto specification describes exactly what kind of error values should be returned
* by which function. Please read the API documentation and comply with the instructions.
* We recommend writing a`<mylibrary>_to_psa_error()` function right in the beginning (see for
* example `CRYS_to_psa_error()` in
* `pkg/driver_cryptocell_310/psa_cryptocell_310/error_conversion.c`).
*
* ### The Build System
* As mentioned before, there are two ways of selecting build time configurations in RIOT: Kconfig
* and Makefiles.
* Kconfig dependency resolution is currently an experimental feature and will at some point
* replace Makefiles. Until then, our implementation needs to support both, which means we need
* to define features and symbols in multiple places.
* Luckily, the modules have the exact same names in both systems, which makes the transfer easier.
* The examples below show both ways.
*
* ### Modules {#module-names}
* In RIOT, module names are generated from path names, so if you create a directory for
* your sourcefiles, the module name will be the same as the directory name. It is possible
* to change that by declaring a new module name in the Makefile by adding the line
* your_module_name`.
*
* If you leave it like this, all sourcefiles in the path corresponding to the module name will be
* built (e.g. if you choose to module `hashes`, all files in `sys/hashes` will be included).
* For better configurability it is possible to add submodules (see
* `sys/hashes/psa_riot_hashes` for example).
* In that case the base module name will be the directory name and each file inside the directory
* becomes its own submodule that must be explicitly chosen. The module name will then be the
* directory name with the file name as a postfix.
* For example:
* @code
* USEMODULE += hashes
* USEMODULE += psa_riot_hashes
* USEMODULE += psa_riot_hashes_sha_256
*
* will build the file at `sys/hashes/psa_riot_hashes/sha_256.c`, but none of the other files in
* the directory).
*
* To enable submodules for your implementation add the following to the directory makefile:
* @code
* BASE_MODULE := psa_<modulename>
* SUBMODULES := 1
* @endcode
*
* We also need to create so-called pseudomodules for each available submodule.
* Those must follow the scheme `psa_<modulename>_<filename>`.
* Where they are declared depends on where your module is located. Pseudomodules in `RIOT/sys` must
* be added in `pseudomodules.inc.mk`.
* When integrating packages or drivers, the pseudomodules can be added in the `Makefile.include`
* file of the individual module's directory (see `pkg/micro-ecc/Makefile.include`).
*
* When adding backends to PSA Crypto, please name your modules in ways that fit within the
* current naming scheme: `psa_<library>_<algorithm>`. Also, when adding software libraries and
* hardware drivers, use the submodule approach. That makes PSA Crypto more configurable.
*
* The drawback of the submodule approach is, that if one of our sourcefiles depends on
* another sourcefile in the same folder, we need to select it explicitly. For example, in
* `pkg/driver_cryptocell_310/psa_cryptocell_310` you can see that there are some common source
* files that all the others use (e.g. for hashes there is a `hashes_common.c` file).
*
* If that is the case for your driver, you need to make sure the modules are selected in
* the Kconfig file as well as the `Makefile.dep` file (see `psa_cryptocell_310/Makefile.dep` or
* `psa_cryptocell_310/Kconfig`).
*
* ### Adding Glue Code {#glue-code}
* We define a number of wrapper APIs, which are called by PSA to invoke crypto backends.
* Software libraries and hardware drivers use the same methods, secure elements are handled
* in a different way (see [Case Example Secure Elements](#porting-secure-elements) for details).
*
* The names, parameters and return values for wrapper methods are defined in header files in
* `sys/psa_crypto/include/psa_<algorithm>.h`.
* The functions declared in those files are the ones that are currently supported by this
* PSA implementation. They will be extended in the future.
*
* You need to implement those functions with glue code calling your library or driver code
* and converting types and error values between PSA and your backend.
* Below is an example of how this might look (it's very reduced, your library may need
* much more glue code).
* @code {.c}
* psa_status_t psa_ecc_p256r1_sign_hash(const psa_key_attributes_t *attributes,
* psa_algorithm_t alg, const uint8_t *key_buffer,
* size_t key_buffer_size, const uint8_t *hash,
* size_t hash_length, uint8_t *signature,
* size_t signature_size, size_t *signature_length)
* {
* int status = <libraryname>_<sign_hash_func>(key_buffer, hash, hash_length,
* signature, signature_length, curve);
*
* if (status != SUCCESS) {
* return <libraryname>_status_to_psa_error(status);
* }
*
* (void)alg;
* (void)attributes;
* (void)key_buffer_size;
* return PSA_SUCCESS;
* }
* @endcode
*
* ### Operation Contexts
* Some cryptographic operations use driver specific context to store the operation state in
* between function calls. These must be defined somewhere. Examples can be found in
* `pkg/driver_cryptocell_310/include/psa_periph_hashes_ctx.h` and
* `sys/include/hashes/psa/riot_hashes.h`.
*
* When defining the contexts for a hardware driver, all you need to do is add a file called
* `psa_periph_<algorithm>_ctx.h` to your driver's include folder and define the available types
* (see supported [types](#supported-types) below).
* Those files are automatically included in `crypto_includes.h` and it is important that they
* always have the same name for each algorithm.
*
* When defining the contexts for a software library, the headerfile should be called
* `<library>_<algorithm>.h` (e.g. `riot_hashes.h`) and must be added to `crypto_includes.h` as
* shown below:
* @code
* #if IS_USED(MODULE_PSA_<LIBRARY>_<ALGORITHM>)
* #include "<library>/<library>_<algorithm>.h"
* #endif
* @endcode
*
* When defining the context types, those must always depend on the specific algorithm module,
* for example
* @code
* #if IS_USED(MODULE_PSA_<LIBRARY>_HASHES_SHA_256)
* #include "path/to/headerfile_containing_the_driver_context_definition"
*
* typedef <library_context_type_t> psa_hashes_sha256_ctx_t;
* #endif
* @endcode
*
* #### Hashes {#supported-types}
* - `psa_hashes_md5_ctx_t`
* - `psa_hashes_sha1_ctx_t`
* - `psa_hashes_sha224_ctx_t`
* - `psa_hashes_sha256_ctx_t`
* - `psa_hashes_sha512_ctx_t`
*
* #### Ciphers
* - `psa_cipher_aes_128_ctx_t`
* - `psa_cipher_aes_192_ctx_t`
* - `psa_cipher_aes_256_ctx_t`
*
* Secure Elements need their own contexts. For this,
* see [Case Example Secure Elements](#porting-secure-elements).
*
* ## Adding a Backend
* The integration of hardware drivers, software libraries and secure element drivers
* differs a bit. Below we describe the necessary steps for each of them.
*
* ### Case Example A Software Library {#porting-software}
* Software libraries are the easiest backends, because they are not platform or hardware
* specific. They can generally run on all platforms in RIOT and we can
* combine different software backends for different operations (we could, for example,
* use the Micro-ECC package for ECC NIST curves and the C25519 package for operations with
* the Curve25519).
*
* Let's say we have an imaginary software library called `FancyCrypt` and want to use
* it as a backend of PSA. We've already added it to RIOT as a third party package in
* `pkg/fancycrypt`.
* Our library provides hashes and elliptic curve operations and to make it accessible to
* PSA Crypto we need to write wrappers for our API calls.
*
* First we create a folder called `psa_fancycrypt` in the package directory. Inside we create
* a file with the name of each operation you want to integrate, e.g. `p256.c` and
* `hashes_sha_224.c` (when adding operations, remember that the path of the files will also
* be the [module name](#module-names), so please comply with the current naming scheme).
*
* In these files we need to implement the methods that are called by PSA as described
* [above](#glue-code).
*
* #### Adding Makefiles
* We add a Makefile to the `psa_fancycrypt` folder with the following content:
* @code {.c}
* BASE_MODULE := psa_fancycrypt
* SUBMODULES := 1
*
* include $(RIOTBASE)/Makefile.base
* @endcode
*
* This tells RIOT that the `psa_fancycrypt` module has submodules, which can be selected
* individually.
*
* In `pkg/fancycrypt` we now need to declare explicit pseudomodules in `Makefile.include` and add
* the `psa_fancycrypt` folder to the source files and the `sys/psa_crypto/include` folder to the
* includes.
* These should be dependent on the PSA Crypto module as shown below.
*
* @code
* ifneq (,$(filter psa_fancycrypt_%, $(USEMODULE)))
* PSEUDOMODULES += psa_fancycrypt_hashes_sha_256
* PSEUDOMODULES += psa_fancycrypt_p256
* DIRS += $(RIOTPKG)/fancycrypt/psa_fancycrypt
* INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
* endif
* @endcode
*
* If the implementation has any dependencies, they need to be added in `Makefile.dep`, for example:
* @code
* USEMODULE += psa_fancycrypt
* USEMODULE += psa_fancycrypt_error_conversion
*
* ifneq (,$(filter psa_fancycrypt_hashes_sha1,$(USEMODULE)))
* USEMODULE += psa_fancycrypt_hashes_common
* endif
* @endcode
*
* #### Adding a Kconfig file
* We add a file called `Kconfig` to the `psa_fancycrypt` folder. Here we declare
* the modules for Kconfig like so:
* @code
* config MODULE_PSA_FANCYCRYPT_HASHES_SHA_256
* bool
* depends on MODULE_PSA_CRYPTO
* select MODULE_PSA_FANCYCRYPT
*
* config MODULE_PSA_FANCYCRYPT_P256
* bool
* depends on MODULE_PSA_CRYPTO
* select MODULE_PSA_FANCYCRYPT
*
* config MODULE_PSA_FANCYCRYPT
* bool
* @endcode
*
* If the implementation has any dependencies, we can select them in this Kconfig file:
* @code
* config MODULE_PSA_FANCYCRYPT_HASHES_SHA_256
* bool
* depends on MODULE_PSA_CRYPTO
* select MODULE_PSA_FANCYCRYPT
* select MODULE_PSA_FANCYCRYPT_HASHES_COMMON
* select MODULE_PSA_FANCYCRYPT_ERROR_CONVERSION
* @endcode
*
* In `pkg/fancycrypt/Kconfig` we need to add the line
* @code
* rsource "psa_fancycrypt/Kconfig"
* @endcode
* at the bottom.
*
* #### Telling PSA Crypto about it
* To be able to choose `fancycrypt` as a PSA backend, we need to add the option to the Kconfig
* and Makefiles of the PSA Crypto Module.
*
* In `sys/psa_crypto/` we need to modify `Kconfig.asymmetric`, `sys/psa_crypto/Kconfig.hashes`,
* `Makefile.dep` and `Makefile.include`.
*
* To `Kconfig.asymmetric` we need to add
* @code
* config MODULE_PSA_ASYMMETRIC_ECC_P256R1_BACKEND_FANCYCRYPT
* bool "FancyCrypt Package"
* select PACKAGE_FANCYCRYPT
* select MODULE_PSA_FANCYCRYPT_P256
* @endcode
* This will expose FancyCrypt as a backend option in PSA and then enable all the necessary
* features, when users select it.
* You need to do the same thing for the hash operation in `Kconfig.hashes`.
*
* To achieve the same thing with Makefiles we need to do this in two places:
* In `Makefile.include` there are some existing pseudomodules for asymmetric crypto and hashes.
* There we need to create the backend modules for FancyCrypt by adding
*
* @code
* PSEUDOMODULES += psa_asymmetric_ecc_p256r1_backend_fancycrypt
* @endcode
*
* and
*
* @code
* PSEUDOMODULES += psa_hash_sha_256_backend_fancycrypt
* @endcode
*
* The automatic module selection happens in `Makefile.dep`. To the place where exiting P256 curves
* and hashes are selected we add cases for our backend modules:
*
* @code
* ifneq (,$(filter psa_asymmetric_ecc_p256r1_backend_fancycrypt,$(USEMODULE)))
* USEPKG += fancycrypt
* USEMODULE += psa_fancycrypt
* USEMODULE += psa_fancycrypt_p256
* endif
* @endcode
*
* Now you should be able to select your package as a backend for PSA Crypto and use it to perform
* operations.
*
* ### Case Example A Hardware Driver {#porting-hardware}
* The first steps of porting a hardware driver are the same as for the software library.
* Only we skip the last part where we add the modules to the PSA Crypto Kconfig and Makefiles
* and do something else instead.
*
* Hardware drivers are treated a little differently, mostly because they are tied to a specific
* platform and users can not just choose a different driver for their accelerator.
* Therefore we just want PSA Crypto to automatically use this driver whenever it runs on the
* corresponding platform, which means that we have to add some additional options and features,
* not only to the driver but also to the CPU it belongs to.
* A good example for this is the [CryptoCell 310 driver](#pkg_driver_cryptocell_310) for the
* accelerator on the [nRF52840 CPU](#cpu_nrf52).
*
* Now, let's say we have a CPU called `myCPU` with an on-chip accelerator called
* `speedycrypt`. Let's say that `speedycrypt` provides hashes and ECC curves.
* The vendor provides a driver, which we already have included in RIOT as a package.
* Also we've followed the steps in the [glue code section](#glue-code) and provide a folder called
* `pkg/driver_speedycrypt/psa_speedycrypt` with the required wrapper files.
* We have also added the module names in a Kconfig file and in the Makefiles.
*
* #### Telling PSA Crypto about it
* This is where we diverge from the software library example. If you take a look at the available
* backends in PSA, you'll notice one with the postfix `*_BACKEND_PERIPH` for each available
* algorithm. **Periph** here is short for *peripheral hardware accelerator*.
* The `*_BACKEND_PERIPH` modules depend on the presence of such an accelerator. They are a generic
* module for all crypto hardware accelerators and will automatically resolve to the driver that is
* associated with the available accelerator.
*
* Before we're able to use it we need to tell RIOT that those hardware features exist for
* our `myCPU` (see `cpu/nrf52/Kconfig` and `cpu/nrf52/Makefile.features` as an example).
* In `cpu/myCPU` we add all the provided features as shown below.
*
* Files we need to touch:
* - `cpu/myCPU/Makefile.features`
* - `cpu/myCPU/Kconfig`
* - `cpu/myCPU/periph/Makefile.dep`
* - `cpu/myCPU/periph/Kconfig`
* - When defining new features: `RIOT/kconfigs/Kconfig.features`
*
* **cpu/myCPU/Makefile.features:**
* @code
* FEATURES_PROVIDED += periph_speedycrypt // General feature for the acclerator
* FEATURES_PROVIDED += periph_hash_sha_256
* FEATURES_PROVIDED += periph_ecc_p256r1
* @endcode
*
* **cpu/myCPU/Kconfig:**
* @code
* config CPU_FAM_MYCPU
* bool
* select CPU_SOME_FEATURES
* ...
* select HAS_PERIPH_HASH_SHA_256
* select HAS_PERIPH_ECC_P256R1
* select HAS_PERIPH_SPEEDYCRYPT
* @endcode
* The `HAS_PERIPH_*` symbols are defined in ``. If your device
* provides capabilities that are not yet defined, you can add them to that file.
*
* Next we need to define selectable modules for this in the `cpu/myCPU/periph` folder, which
* then automatically enable the driver. An example for this is `cpu/nrf52/periph`.
* We add the following to the `cpu/myCPU/periph/Kconfig` file and `cpu/myCPU/periph/Makefile.dep`:
*
* **cpu/myCPU/periph/Makefile.dep:**
* @code
* ifneq (,$(filter periph_hash_sha_256,$(USEMODULE)))
* USEPKG += driver_speedycrypt
* USEMODULE += psa_speedycrypt_hashes_sha256
* endif
* @endcode
*
* **cpu/myCPU/periph/Kconfig:**
* @code
* config MODULE_PERIPH_FANCYCRYPT
* bool
* depends on HAS_PERIPH_FANCYCRYPT
* select PACKAGE_DRIVER_FANCYCRYPT
*
* config MODULE_PERIPH_HASH_SHA_256
* bool
* depends on HAS_PERIPH_HASH_SHA_256
* select MODULE_PERIPH_SPEEDYCRYPT
* select MODULE_PSA_SPEEDYCRYPT_HASHES_SHA256
* @endcode
*
* Here we basically say "If the user chooses the `periph_hash_sha_256 module`, also select the
* `periph_speedycrypt` feature, which will then enable the speedycrypt driver". Of course you need
* to do this for all your available features.
*
* Now, if you build PSA Crypto with default configurations, it should automatically detect that
* your board has a hardware accelerator for hashes and ECC operations and build the hardware
* driver as a backend.
*
* ### Case Example A Secure Element Driver {#porting-secure-elements}
* Secure elements (SEs) are handled almost completely separate from the other backends. When we use
* software libraries or hardware drivers, we only build one implementation per algorithm.
* When it comes to secure elements we want to be able to build them in addition to the other
* backends and we may want to connect and use more than one of them at the same time.
* Another difference is that when using software libraries and hardware drivers, PSA handles the
* storage of key material. When using SEs, keys are stored on the SE, which means, we need
* additional functionality for the key management.
*
* An existing example in RIOT is the Microchip ATECCX08A device family, whose driver can be found
* in `pkg/cryptoauthlib`.
*
* PSA Crypto has an integrated SE driver registry, which stores all registered drivers in a list.
* When an application calls a cryptographic operation that's supposed to be performed by a secure
* element, the registry will find the correct driver in the list and PSA will invoke the operation.
* Each driver is stored with a context that contains persistent as well as transient driver data.
* Transient driver data can be anything the driver needs to function. Persistent data is supposed
* to be used to keep track of how many keys are stored on the device and if there is still some
* free space available.
*
* @note Currently PSA does not support persistent storage, so the persistent driver data
* is not really persistent, yet. Once persistent storage is implemented, this data
* will be stored, so the implementation can find already existing keys again after
* a reboot.
*
* For this example we integrate an imaginary SE called `superSE`, which comes with a driver called
* `superSE_lib`. Again, we assume that we have already added the driver as a package in RIOT and it
* can be found at `pkg/superse_lib`.
*
* #### Adding the Glue Code
* Secure element drivers need to implement a different API than the other backends. It is defined
* [here](#sys_psa_crypto_se_driver).
* In our package folder we now create a new folder called `psa_superse_driver` and add a source
* file called `psa_superse_lib_driver.c`. Here we now implement glue code for all the cryptographic
* operations our SE supports.
*
* You will notice that the SE interface also provides some key management functions. This is
* because keys are stored on the device and PSA can not access the memory and key data itself,
* but needs to tell the driver to do it.
*
* ### Operation Contexts
* Some operations need driver specific contexts. For secure elements these are wrapped in types
* defined in `crypto_contexts.h` (currently only `psa_se_cipher_context_t` is supported).
* In this header file add operation contexts that belong to your driver to the available SE
* context unions as shown in the example below:
*
* @code
* typedef struct {
* union driver_context {
* unsigned dummy;
* #if IS_USED(MODULE_PSA_SECURE_ELEMENT_ATECCX08A) || defined(DOXYGEN)
* atca_aes_cbc_ctx_t atca_aes_cbc;
* #endif
* #if IS_USED(MODULE_PSA_SECURE_ELEMENT_SUPERSE) || defined(DOXYGEN)
* superse_cipher_ctx_t superse_aes_cbc;
* #endif
* } drv_ctx;
* } psa_se_cipher_context_t;
* @endcode
*
* #### Allocation
* The first thing PSA will do, when an application creates a key on an SE, is ask the driver to
* find a free key slot on the device. This is what the `allocate` function is for. How exactly
* the slot is allocated, depends on the driver.
* It may be possible to query that information directly from the device. If that is not possible,
* we can use the persistent data stored in the driver context. An example for this can be
* found in `pkg/cryptoauthlib/psa_atca_driver/psa_atca_se_driver.c`.
* This example requires the user to provide information about the configurations for each key slot,
* which is then stored in the persistent driver data and used for key management (for a better
* description read [Using Cryptoauthlib as a backend for PSA Crypto](#psa-cryptoauthlib)).
* At this point you can decide what the best approach for your device is.
*
* The `allocate` function should then return some reference to the slot it has allocated
* for the key (possibly a pointer or a slot number). Next PSA Crypto will invoke the `import`
* or `generate` function to store a key.
*
* #### Using Persistent Data
* When you want to use persistent data to keep track of keys, you should utilize the
* `psa_se_config_t` structure, which is declared in `crypto_se_config.h`.
* You can define a structure that can hold your device configuration and make sure it is available
* then your SE is used.
*
* #### Making the Methods Available
* At the bottom of the wrapper code, define structures with pointers to the available methods.
* For example if you have implemented a `superse_allocate` and `superse_generate_key` function,
* you need to add a `psa_drv_se_key_management_t` structure as shown below. Fill the unimplemented
* methods with `NULL` pointers.
* The last structure should be a `psa_drv_se_t` struct containing pointers to the other structures.
* That one will be stored during driver registration to get access to all the implemented
* functions.
*
* @code {.c}
* static psa_drv_se_key_management_t superse_key_management = {
* .p_allocate = superse_allocate,
* .p_validate_slot_number = NULL,
* .p_import = NULL,
* .p_generate = superse_generate_key,
* .p_destroy = NULL,
* .p_export = NULL,
* .p_export_public = NULL
* };
*
* psa_drv_se_t superse_methods = {
* .hal_version = PSA_DRV_SE_HAL_VERSION,
* .persistent_data_size = 0,
* .p_init = NULL,
* .key_management = &superse_key_management,
* .mac = NULL,
* .cipher = NULL,
* .aead = NULL,
* .asymmetric = NULL,
* .derivation = NULL
* };
* @endcode
*
* You should do this for all available functions. The structures for the functions are
* declared in `sys/psa_crypto/include/psa_crypto_se_driver.h`.
*
* #### Driver Registration
* At start-up all secure element drivers need to be registered with the PSA SE management module.
* This happens by calling `psa_register_secure_element()` during the automatic driver
* initialization in RIOT.
* When you added support for our device to RIOT, you should have implemented an
* `auto_init_<device>` function, which initializes the connected devices.
* In this function, after initializing a device, you should call `psa_register_secure_element()`
* and pass the device's location value, and pointers to the `psa_drv_se_t` structure,
* the persistent data and some device specific context.
* An example implementation of this can be seen in `sys/auto_init/security/auto_init_atca.c`.
*
* #### Telling PSA Crypto about it
* To be able to choose our `superSE` during configuration, we need to define the corresponding
* modules in the Kconfig files and Makefiles.
*
* To `pkg/super_se_lib/Kconfig` we add something like
* @code
* config MODULE_PSA_SUPERSE_DRIVER
* bool
* depends on PACKAGE_SUPERSE_LIB
* default y if MODULE_PSA_CRYPTO
* select PSA_KEY_MANAGEMENT
* @endcode
* This tells the build system that whenever this driver and PSA Crypto are used at the same time,
* the wrapper and the PSA key management module are needed, too.
*
* To `sys/psa_crypto/psa_se_mgmt/Kconfig` we add a menu for the SE like so:
* @code
* menuconfig MODULE_PSA_SECURE_ELEMENT_SUPERSE
* bool "Our Vendor's SuperSE"
* select PACKAGE_SUPERSE_LIB
* depends on <whatever protocol is needed for communication, e.g. HAS_PERIPH_I2C>
* help
* <Some helpful information about this module>
* @endcode
* This makes our driver selectable whenever an application configuration selects the PSA secure
* element module.
*
* As described in the [Configuration Section](#configuration-keys), references to keys on secure
* elements are stored by PSA in a different type of key slot than other keys.
* The slot for protected keys usually only contains a slot number or address and not the actual
* key, which requires a lot less memory space.
*
* **BUT:** If your secure element supports asymmetric cryptography and exports a public key part
* during key generation, that key part must be stored somewhere. This is why there needs to be
* an option to tell PSA Crypto that an application is going to perform asymmetric operations.
* Only if that option is selected, the protected key slots will have the space to store a public
* key.
*
* For this we need to add the following to the `superSE` menu:
* @code
* config MODULE_PSA_SECURE_ELEMENT_SUPERSE_ECC_P256
* bool "Our Vendor's Elliptic Curve P256"
* select PSA_KEY_SIZE_256
* select MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC
* depends on MODULE_PSA_SECURE_ELEMENT_SUPERSE
* @endcode
* This tells us, what size a key slot should have to store the public key. If your SE supports
* other curves, you need to modify this accordingly or add more of them.
*
* Now we need to add the same to the Makefiles. In `Makefile.include` we add the source file path
* and the PSA include folders and define the new available pseudomodules:
* @code
* ifneq (,$(filter psa_crypto,$(USEMODULE)))
* DIRS += $(RIOTPKG)/superse_lib/psa_superse_driver
* INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
* PSEUDOMODULES += psa_secure_element_superse
* PSEUDOMODULES += psa_secure_element_superse_ecc_p256
* endif
* @endcode
*
* In `Makefile.dep` we automatically add required modules when PSA Crypto and the ECC curve
* module are chosen:
* @code
* ifneq (,$(filter psa_crypto,$(USEMODULE)))
* USEMODULE += psa_superse_driver
* endif
*
* ifneq (,$(filter psa_secure_element_superse_ecc_p256, $(USEMODULE)))
* USEMODULE += psa_secure_element_asymmetric
* endif
*
* Now the secure element should be available for use with PSA Crypto.
* @endcode
*/

View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_cipher PSA Wrapper Functions: Cipher
* @{
*
* @file psa_ciphers.h
* @brief Function declarations for low level wrapper functions for cipher operations.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CIPHERS_H
#define PSA_CIPHERS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "psa/crypto_contexts.h"
/**
* @brief Low level wrapper function to call a driver for an AES 128 CBC encryption.
* See @ref psa_cipher_encrypt()
*
* @param attributes
* @param key_buffer
* @param key_buffer_size
* @param alg
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return @ref psa_status_t
*/
psa_status_t psa_cipher_cbc_aes_128_encrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
/**
* @brief Low level wrapper function to call a driver for an AES 128 CBC decryption.
* See @ref psa_cipher_decrypt()
*
* @param attributes
* @param key_buffer
* @param key_buffer_size
* @param alg
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return @ref psa_status_t
*/
psa_status_t psa_cipher_cbc_aes_128_decrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
/**
* @brief Low level wrapper function to call a driver for an AES 192 CBC encryption.
* See @ref psa_cipher_encrypt()
*
* @param attributes
* @param key_buffer
* @param key_buffer_size
* @param alg
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return @ref psa_status_t
*/
psa_status_t psa_cipher_cbc_aes_192_encrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
/**
* @brief Low level wrapper function to call a driver for an AES 256 CBC encryption.
* See @ref psa_cipher_encrypt()
*
* @param attributes
* @param key_buffer
* @param key_buffer_size
* @param alg
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return psa_status_t
*/
psa_status_t psa_cipher_cbc_aes_256_encrypt(const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
#ifdef __cplusplus
}
#endif
#endif /* PSA_CIPHERS_H */
/** @} */

View File

@ -0,0 +1,201 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_alg_disp PSA Crypto Algorithm Dispatcher
* @{
*
* @file psa_crypto_algorithm_dispatch.h
* @brief Function declarations for PSA Crypto algorithm dispatcher
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_ALGORITHM_DISPATCH_H
#define PSA_CRYPTO_ALGORITHM_DISPATCH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include "kernel_defines.h"
#include "psa/crypto.h"
#include "psa_crypto_slot_management.h"
/**
* @brief Dispatch a hash setup function to a specific backend.
* See @ref psa_hash_setup()
*
* @param operation
* @param alg
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_hash_setup(psa_hash_operation_t *operation,
psa_algorithm_t alg);
/**
* @brief Dispatch a hash update function to a specific backend.
* See @ref psa_hash_update()
*
* @param operation
* @param input
* @param input_length
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_hash_update(psa_hash_operation_t *operation,
const uint8_t *input,
size_t input_length);
/**
* @brief Dispatch a hash finish function to a specific backend.
* See @ref psa_hash_finish()
*
* @param operation
* @param hash
* @param hash_size
* @param hash_length
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_hash_finish(psa_hash_operation_t *operation,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
/**
* @brief Dispatch a hash signature function to a specific backend.
* See @ref psa_sign_hash()
*
* @param attributes
* @param alg
* @param slot
* @param hash
* @param hash_length
* @param signature
* @param signature_size
* @param signature_length
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length);
/**
* @brief Dispatch a hash verification function to a specific backend.
* See @ref psa_verify_hash()
*
* @param attributes
* @param alg
* @param slot
* @param hash
* @param hash_length
* @param signature
* @param signature_length
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_verify_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length);
/**
* @brief Dispatch the key generation function to a specific backend.
* See @ref psa_generate_key()
*
* @param attributes
* @param slot
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_generate_key( const psa_key_attributes_t *attributes,
psa_key_slot_t *slot);
/**
* @brief Dispatch a cipher encrypt function to a specific backend.
* See @ref psa_cipher_encrypt()
*
* @param attributes
* @param alg
* @param slot
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
/**
* @brief Dispatch a cipher decrypt function to a specific backend.
* See @ref psa_cipher_decrypt()
*
* @param attributes
* @param alg
* @param slot
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
/**
* @brief Dispatch a mac computation function to a specific backend.
* See @ref psa_mac_compute()
*
* @param attributes
* @param alg
* @param slot
* @param input
* @param input_length
* @param mac
* @param mac_size
* @param mac_length
* @return @ref psa_status_t
*/
psa_status_t psa_algorithm_dispatch_mac_compute(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length);
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_ALGORITHM_DISPATCH_H */
/** @} */

View File

@ -0,0 +1,230 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_loc_disp PSA Crypto Location Dispatcher
* @{
*
* @file psa_crypto_location_dispatch.h
* @brief Function declarations for the PSA Crypto location dispatcher.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_LOCATION_DISPATCH_H
#define PSA_CRYPTO_LOCATION_DISPATCH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
#include "kernel_defines.h"
#include "psa/crypto.h"
/**
* @brief Dispatch call of a hash signature function to a location specific backend.
* See psa_sign_hash()
*
* @param attributes
* @param alg
* @param slot
* @param hash
* @param hash_length
* @param signature
* @param signature_size
* @param signature_length
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length);
/**
* @brief Dispatch call of a hash verification function to a location specific backend.
* See psa_verify_hash()
*
* @param attributes
* @param alg
* @param slot
* @param hash
* @param hash_length
* @param signature
* @param signature_length
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_verify_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length);
/**
* @brief Dispatch call of a mac computation function to a location specific backend.
* See psa_mac_compute()
*
* @param attributes
* @param alg
* @param slot
* @param input
* @param input_length
* @param mac
* @param mac_size
* @param mac_length
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_mac_compute(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length);
/**
* @brief Dispatch call of the key generation function to a location specific backend.
* See psa_generate_key()
*
* @param attributes
* @param slot
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_generate_key(const psa_key_attributes_t *attributes,
psa_key_slot_t *slot);
/**
* @brief Dispatch call of the key import function to a location specific backend.
* See psa_import_key()
*
* @param attributes
* @param data
* @param data_length
* @param slot
* @param bits
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attributes,
const uint8_t *data, size_t data_length,
psa_key_slot_t *slot, size_t *bits);
/**
* @brief Dispatch call of a cipher encrypt setup function to a location specific backend.
* See psa_cipher_setup()
*
* @param operation
* @param attributes
* @param slot
* @param alg
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_cipher_encrypt_setup( psa_cipher_operation_t *operation,
const psa_key_attributes_t *attributes,
const psa_key_slot_t *slot,
psa_algorithm_t alg);
/**
* @brief Dispatch call of a cipher decrypt setup function to a location specific backend.
* See psa_cipher_setup()
*
* @param operation
* @param attributes
* @param slot
* @param alg
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_cipher_decrypt_setup(psa_cipher_operation_t *operation,
const psa_key_attributes_t *attributes,
const psa_key_slot_t *slot,
psa_algorithm_t alg);
/**
* @brief Dispatch call of a function to set a cipher IV to a location specific backend.
* See psa_cipher_set_iv()
*
* @param operation
* @param iv
* @param iv_length
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_cipher_set_iv( psa_cipher_operation_t *operation,
const uint8_t *iv,
size_t iv_length);
/**
* @brief Dispatch call of a cipher encrypt function to a location specific backend.
* See psa_cipher_encrypt()
*
* @param attributes
* @param alg
* @param slot
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
/**
* @brief Dispatch call of a cipher decrypt function to a location specific backend.
* See psa_cipher_decrypt()
*
* @param attributes
* @param alg
* @param slot
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length);
/**
* @brief Dispatch call of a random number generator to a specific backend.
* See psa_generate_random()
*
* @param output
* @param output_size
* @return psa_status_t
*/
psa_status_t psa_location_dispatch_generate_random(uint8_t *output,
size_t output_size);
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_LOCATION_DISPATCH_H */
/** @} */

View File

@ -0,0 +1,172 @@
/*
* Copyright (C) 2022 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @{
*
* @file psa_crypto_operation_encoder.h
* @brief Macros used to map PSA akgorithms, key types and key sizes to specific key types
* and operations to call the corresponding driver functions.
*
* @note Currently this only supports a small number of operations. It should be expanded as
* needed as this implementation increases support for more operations.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_OPERATION_ENCODER_H
#define PSA_CRYPTO_OPERATION_ENCODER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "psa_crypto_slot_management.h"
/**
* @brief Unknown or invalid operation
*/
#define PSA_INVALID_OPERATION (0xFF)
/**
* @brief Enum encoding available cipher operations.
*
* @details To be expanded with the development of this implementation.
*/
typedef enum {
PSA_CBC_NO_PAD_AES_128,
PSA_CBC_NO_PAD_AES_192,
PSA_CBC_NO_PAD_AES_256,
PSA_CBC_PKCS7_AES_256
} psa_cipher_op_t;
/**
* @brief Enum encoding available asymmetric key types and sizes.
*
* @details To be expanded with the development of this implementation.
*/
typedef enum {
PSA_ECC_P160_K1,
PSA_ECC_P160_R1,
PSA_ECC_P160_R2,
PSA_ECC_P192_K1,
PSA_ECC_P192_R1,
PSA_ECC_P224_K1,
PSA_ECC_P224_R1,
PSA_ECC_P256_K1,
PSA_ECC_P256_R1,
PSA_ECC_P384_R1,
PSA_ECC_P521_R1,
PSA_ECC_FRP,
PSA_ECMONT_255,
PSA_ECMONT_448
} psa_asym_key_t;
/**
* @brief Combine an ECC 192 key type with a given curve.
*
* @param curve Must be a curve of type @ref psa_ecc_family_t
*
* @return @ref psa_asym_key_t
* @return @ref PSA_INVALID_OPERATION @c curve is not compatible with key size
*/
#define GET_ECC_KEY_TYPE_192(curve) \
((curve == PSA_ECC_FAMILY_SECP_R1) ? PSA_ECC_P192_R1 : \
PSA_INVALID_OPERATION)
/**
* @brief Combine an ECC 265 key type with a given curve.
*
* @param curve Must be a curve of type @ref psa_ecc_family_t
*
* @return @ref psa_asym_key_t
* @return @ref PSA_INVALID_OPERATION @c curve is not compatible with key size
*/
#define GET_ECC_KEY_TYPE_256(curve) \
((curve == PSA_ECC_FAMILY_SECP_R1) ? PSA_ECC_P256_R1 : \
PSA_INVALID_OPERATION)
/**
* @brief Map an ECC 192 key to a given curve according to its type and size.
*
* @param bits Key size of type @ref psa_key_bits_t
* @param curve Must be a curve of type @ref psa_ecc_family_t
*
* @return @ref psa_asym_key_t
* @return @ref PSA_INVALID_OPERATION @c curve and @c bits are incompatible
*/
#define PSA_ENCODE_ECC_KEY_TYPE(bits, curve) \
((bits == 256) || (bits == 520) ? GET_ECC_KEY_TYPE_256(curve) : \
(bits == 192) || (bits == 392) ? GET_ECC_KEY_TYPE_192(curve) : \
PSA_INVALID_OPERATION)
/**
* @brief Combine algorithm, and key type with a key size of 128 bits.
*
* @param alg Algorithm of type @ref psa_algorithm_t.
* @param type Key type of type @ref psa_key_type_t
*
* @return @ref psa_cipher_op_t
* @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size
*/
#define GET_CIPHER_OPERATION_128(alg, type) \
(((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_128 : \
PSA_INVALID_OPERATION)
/**
* @brief Combine algorithm, and key type with a key size of 192 bits.
*
* @param alg Algorithm of type @ref psa_algorithm_t.
* @param type Key type of type @ref psa_key_type_t
*
* @return @ref psa_cipher_op_t
* @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size
*/
#define GET_CIPHER_OPERATION_192(alg, type) \
(((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_192 : \
PSA_INVALID_OPERATION)
/**
* @brief Combine algorithm, and key type with a key size of 256 bits.
*
* @param alg Algorithm of type @ref psa_algorithm_t.
* @param type Key type of type @ref psa_key_type_t
*
* @return @ref psa_cipher_op_t
* @return @ref PSA_INVALID_OPERATION @c alg, and @c type are incompatible with the key size
*/
#define GET_CIPHER_OPERATION_256(alg, type) \
(((alg == PSA_ALG_CBC_NO_PADDING) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_NO_PAD_AES_256 : \
((alg == PSA_ALG_CBC_PKCS7) && (type == PSA_KEY_TYPE_AES)) ? PSA_CBC_PKCS7_AES_256 : \
PSA_INVALID_OPERATION)
/**
* @brief Map algorithm, key size and type to a specific operation.
*
* @param alg Algorithm of type @ref psa_algorithm_t.
* @param bits Size of the used key of type @ref psa_key_bits_t
* @param type Key type of type @ref psa_key_type_t
*
* @return @ref psa_cipher_op_t
* @return @ref PSA_INVALID_OPERATION @c alg, @c bits and @c type are not compatible
*/
#define PSA_ENCODE_CIPHER_OPERATION(alg, bits, type) \
((bits == 128) ? GET_CIPHER_OPERATION_128(alg, type) : \
(bits == 192) ? GET_CIPHER_OPERATION_192(alg, type) : \
(bits == 256) ? GET_CIPHER_OPERATION_256(alg, type) : \
PSA_INVALID_OPERATION)
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_OPERATION_ENCODER_H */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,207 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @defgroup psa_crypto_se_mgmt PSA Crypto SE Management
* @{
*
* @file psa_crypto_se_management.h
* @brief PSA Secure Element management function declarations
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_SE_MANAGEMENT_H
#define PSA_CRYPTO_SE_MANAGEMENT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "psa_crypto_se_driver.h"
/**
* @brief Maximum number of available secure elements.
*/
#ifndef CONFIG_PSA_MAX_SE_COUNT
#define CONFIG_PSA_MAX_SE_COUNT (1)
#endif /* CONFIG_PSA_MAX_SE_COUNT */
/**
* @brief Maximum supported number of secure elements
*/
#define PSA_MAX_SE_COUNT (CONFIG_PSA_MAX_SE_COUNT)
/**
* @brief Internal secure element driver context.
*
* @details This is the same structure as @ref psa_drv_se_context_t, with the difference that it is
* also writeable for the implementation.
*
* This structure is not to be used by applications, only by the PSA Crypto implementation.
*/
typedef struct {
void * persistent_data; /**< Driver specific persistent data */
size_t persistent_data_size; /**< Size of persistent data in bytes */
uintptr_t transient_data; /**< Driver specific transient data */
} psa_drv_se_internal_context_t;
/**
* @brief Structure containing secure element driver data and contexts.
*/
struct psa_se_drv_data_s {
psa_key_location_t location; /**< Location value assigned to driver */
const psa_drv_se_t *methods; /**< Methods implemented by driver */
union {
psa_drv_se_internal_context_t internal; /**< Internally writable SE driver context */
psa_drv_se_context_t context; /**< SE driver context, read only */
} ctx; /**< SE driver context */
};
/**
* @brief Encodes the secure element driver data
*/
typedef struct psa_se_drv_data_s psa_se_drv_data_t;
/**
* @brief Register a secure element driver with the SE management.
*
* @details This function is called by the @c auto_init module during boot.
*
* @param location Location the driver should be registered with,
* of type @ref psa_key_location_t
* @param methods Structure of available driver entry points of the driver
* @param psa_se_configuration Pointer to a secure element configuration structure
* @param drv_transient_data Transient driver data to be used by the driver
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_INVALID_ARGUMENT The location value is invalid
* @return @ref PSA_ERROR_NOT_SUPPORTED
* @return @ref PSA_ERROR_INSUFFICIENT_MEMORY
* @return @ref PSA_ERROR_ALREADY_EXISTS *
*/
psa_status_t psa_register_secure_element(psa_key_location_t location,
const psa_drv_se_t *methods,
void *psa_se_configuration,
const void *drv_transient_data);
/**
* @brief Get the driver data of a specified driver
*
* @param lifetime Lifetime value of type @ref psa_key_lifetime_t of the key to be used
*
* @return @ref psa_se_drv_data_t* Pointer to the driver data
* @return @c NULL if no driver exists with this location
*/
psa_se_drv_data_t *psa_get_se_driver_data(psa_key_lifetime_t lifetime);
/**
* @brief Get the driver entry points and context of a specified driver
*
* @param lifetime Lifetime value of type @ref psa_key_lifetime_t of the key to be used
* @param p_methods Pointer that will reference the driver methods
* @param p_drv_context Pointer that will reference the driver context
*
* @return 1 if a driver was found
* @return 0 if no driver exists with this location
*/
int psa_get_se_driver( psa_key_lifetime_t lifetime,
const psa_drv_se_t **p_methods,
psa_drv_se_context_t **p_drv_context);
/**
* @brief Get the driver entry points of a specified driver
*
* @param driver Driver data of type @ref psa_se_drv_data_t containing the entry points
*
* @return const psa_drv_se_t*
*/
const psa_drv_se_t *psa_get_se_driver_methods(const psa_se_drv_data_t *driver);
/**
* @brief Get the driver context of a specified driver
*
* @param driver Driver data of type @ref psa_se_drv_data_t containing the context
*
* @return @ref psa_drv_se_context_t*
*/
psa_drv_se_context_t *psa_get_se_drv_context(psa_se_drv_data_t *driver);
/**
* @brief Find an empty key slot on a secure element appropriate to the key attributes
*
* @param attributes @ref psa_key_attributes_t containing the attributes of the key to be created
* @param method The method used to create the key (see @ref psa_key_creation_method_t)
* @param driver Pointer to the driver for the SE the key should be created on
* @param slot_number Pointer that will contain the slot number of the free SE slot
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_CORRUPTION_DETECTED
* @return @ref PSA_ERROR_NOT_SUPPORTED
*/
psa_status_t psa_find_free_se_slot( const psa_key_attributes_t *attributes,
psa_key_creation_method_t method,
psa_se_drv_data_t *driver,
psa_key_slot_number_t *slot_number);
/**
* @brief Destroy the key on a secure element
*
* @note Some secure elements may not support this operation.
*
* @param driver Driver of the SE containing the key to be destroyed
* @param slot_number Slot number of the key that is to be destroyed
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_NOT_PERMITTED
*/
psa_status_t psa_destroy_se_key(psa_se_drv_data_t *driver,
psa_key_slot_number_t slot_number);
/**
* @brief Load SE data from persistent memory
*
* @note This operation is not yet supported by this implementation
*
* @param driver Pointer to the driver data the loaded data should be stored in
*
* @return @ref PSA_ERROR_NOT_SUPPORTED
*/
psa_status_t psa_load_se_persistent_data(const psa_se_drv_data_t *driver);
/**
* @brief Save SE data to persistent memory
*
* @note This operation is not yet supported by this implementation
*
* @param driver Pointer to the driver data containing the data to be saved
*
* @return @ref PSA_ERROR_NOT_SUPPORTED
*/
psa_status_t psa_save_se_persistent_data(const psa_se_drv_data_t *driver);
/**
* @brief Destroy SE data in persistent memory
*
* @note This operation is not yet supported by this implementation
*
* @param location Location of the data that should be destroyed
*
* @return @ref PSA_ERROR_NOT_SUPPORTED
*/
psa_status_t psa_destroy_se_persistent_data(psa_key_location_t location);
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_SE_MANAGEMENT_H */
/**@}*/

View File

@ -0,0 +1,262 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_slot_mgmt PSA Crypto Key Slot Management
* @{
*
* @file psa_crypto_slot_management.h
* @brief PSA key slot management function declarations
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_CRYPTO_SLOT_MANAGEMENT_H
#define PSA_CRYPTO_SLOT_MANAGEMENT_H
#ifdef __cplusplus
extern "C" {
#endif
#include "clist.h"
#include "psa/crypto.h"
#include "psa_crypto_se_management.h"
/**
* @brief Number of allocated slots for keys in protected memory or secure elements.
*/
#define PSA_PROTECTED_KEY_COUNT (CONFIG_PSA_PROTECTED_KEY_COUNT)
/**
* @brief Number of allocated slots for asymmetric key pairs.
*/
#define PSA_ASYMMETRIC_KEYPAIR_COUNT (CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT)
/**
* @brief Number of allocated slots for single keys in local memory.
*/
#define PSA_SINGLE_KEY_COUNT (CONFIG_PSA_SINGLE_KEY_COUNT)
/**
* @brief Complete number of available key slots
*/
#define PSA_KEY_SLOT_COUNT (PSA_PROTECTED_KEY_COUNT + \
PSA_ASYMMETRIC_KEYPAIR_COUNT + \
PSA_SINGLE_KEY_COUNT)
/**
* @brief Minimum key id for volatile keys.
*
* @details This is used to assign volatile identifiers to created keys.
*/
#define PSA_KEY_ID_VOLATILE_MIN (PSA_KEY_ID_VENDOR_MIN)
/**
* @brief Maximum key id for volatile keys.
*
* @details This is the maximum volatile identifiers that can be assigned to created keys.
*/
#define PSA_KEY_ID_VOLATILE_MAX (PSA_KEY_ID_VENDOR_MAX)
/**
* @brief Structure of a virtual key slot in local memory.
*
* @details A slot contains key attributes, a lock count and the @c key_data structure.
* @c key_data consists of the size of the stored key in bytes and a @c uint8_t data array
* large enough to store the largest key used in the current build. This type of key slot
* contains symmetric keys, asymmetric public keys or unstructured data.
*/
typedef struct {
clist_node_t node; /**< List node to link slot in global list */
size_t lock_count; /**< Number of entities accessing the slot */
psa_key_attributes_t attr; /**< Attributes associated with the stored key */
/** Structure containing key data */
struct key_data {
uint8_t data[PSA_MAX_KEY_DATA_SIZE]; /**< Key data buffer */
size_t data_len; /**< Size of actual key data in bytes */
} key; /**< Key data structure */
} psa_key_slot_t;
/**
* @brief Initializes the allocated key slots and prepares the internal key slot lists.
*/
void psa_init_key_slots(void);
/**
* @brief Check whether a key identifier is a volatile key identifier.
*
* @param key_id Key identifier to test.
*
* @return 1 The key identifier is a volatile key identifier.
* @return 0 The key identifier is not a volatile key identifier.
*/
static inline int psa_key_id_is_volatile(psa_key_id_t key_id)
{
return ((key_id >= PSA_KEY_ID_VOLATILE_MIN) &&
(key_id <= PSA_KEY_ID_VOLATILE_MAX));
}
/**
* @brief Check whether a key slot is locked
*
* @param slot Pointer to the slot to be checked
*
* @return 1 if slot is locked, otherwise 0
*/
static inline int psa_is_key_slot_locked(psa_key_slot_t *slot)
{
return (slot->lock_count > 0);
}
/**
* @brief Get slot number in protected memory
*
* @param slot Pointer to the slot containing the protected slot number
* @return @ref psa_key_slot_number_t Key slot number stored in the input slot
*/
psa_key_slot_number_t * psa_key_slot_get_slot_number(const psa_key_slot_t *slot);
/**
* @brief Check whether a key is stored on an external device
*
* @param lifetime Lifetime value of the key that's supposed to be checked
*
* @return int
* @return 1 if key is stored on external device, otherwise 0
*/
static inline int psa_key_lifetime_is_external(psa_key_lifetime_t lifetime)
{
return (PSA_KEY_LIFETIME_GET_LOCATION(lifetime) != PSA_KEY_LOCATION_LOCAL_STORAGE);
}
/**
* @brief Wipe volatile key slot and its contents. Wiped key slots can be reused.
*
* @param slot Pointer to the key slot to be wiped
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_DOES_NOT_EXIST
*/
psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot);
/**
* @brief Wipe all existing volatile key slots.
*/
void psa_wipe_all_key_slots(void);
/**
* @brief Find a key slot in local memory and lock it.
*
* @param id ID of the key to be used
* @param slot Pointer to the slot the key is stored in
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_DOES_NOT_EXIST
* @return @ref PSA_ERROR_NOT_SUPPORTED
*/
psa_status_t psa_get_and_lock_key_slot(psa_key_id_t id, psa_key_slot_t **slot);
/**
* @brief Find a currently empty key slot that is appropriate for the key.
*
* @param id Key ID of the newly generated or imported key
* @param attr Attributes of the key that is supposed to be stored in the slot
* @param p_slot Pointer to the empty slot in memory
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_INSUFFICIENT_STORAGE
*/
psa_status_t psa_allocate_empty_key_slot( psa_key_id_t *id,
const psa_key_attributes_t *attr,
psa_key_slot_t **p_slot);
/**
* @brief Increase lock count
*
* @param slot Slot to be locked
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_CORRUPTION_DETECTED
*/
psa_status_t psa_lock_key_slot(psa_key_slot_t *slot);
/**
* @brief Decrease lock count
*
* @param slot Slot to be unlocked
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_CORRUPTION_DETECTED
*/
psa_status_t psa_unlock_key_slot(psa_key_slot_t *slot);
/**
* @brief Check if key location exists
*
* @param lifetime Lifetime value of the key to be validated
* @param driver Pointer to driver assigned to the existing key location, if it exists
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_INVALID_ARGUMENT
*/
psa_status_t psa_validate_key_location( psa_key_lifetime_t lifetime,
psa_se_drv_data_t **driver);
/**
* @brief Validate key persistence. Currently only volatile keys are supported.
*
* @param lifetime Lifetime of key to be validated
*
* @return @ref PSA_SUCCESS
* @return @ref PSA_ERROR_NOT_SUPPORTED
*/
psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime);
/**
* @brief Check if provided key ID is either a valid user ID or vendor ID
*
* @param id ID of key to be validated
* @param vendor If ID is supposed to be user or vendor ID
*
* @return 1 if valid
* @return 0 if invalid
*/
int psa_is_valid_key_id(psa_key_id_t id, int vendor);
/**
* @brief Get key data and key size from key slot
*
* @param slot Slot the desired key is stored in
* @param key_data Pointer to key data
* @param key_bytes Pointer to key data size in bytes
*
* @return Size of @p key_data in bytes.
*/
size_t psa_get_key_data_from_key_slot(const psa_key_slot_t *slot,
uint8_t **key_data,
size_t **key_bytes);
/**
* @brief Get public key data and size from key slot
*
* @param slot Slot the desired key is stored in
* @param pubkey_data Pointer to key data
* @param pubkey_data_len Pointer to key data size in bytes
*/
void psa_get_public_key_data_from_key_slot( const psa_key_slot_t *slot,
uint8_t **pubkey_data,
size_t **pubkey_data_len);
#ifdef __cplusplus
}
#endif
#endif /* PSA_CRYPTO_SLOT_MANAGEMENT_H */
/**@}*/

View File

@ -0,0 +1,198 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_ecc PSA Wrapper Functions: ECC
* @{
*
* @file psa_ecc.h
* @brief Function declarations for low level wrapper functions for ECC operations.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_ECC_H
#define PSA_ECC_H
#ifdef __cplusplus
extern "C" {
#endif
#include "psa/crypto.h"
#include "kernel_defines.h"
/**
* @brief Low level wrapper function to call a driver for an ECC key generation
* with a SECP 192 R1 key.
* See @ref psa_generate_key()
*
* @param attributes
* @param priv_key_buffer
* @param pub_key_buffer
* @param priv_key_buffer_length
* @param pub_key_buffer_length
* @return @ref psa_status_t
*/
psa_status_t psa_generate_ecc_p192r1_key_pair( const psa_key_attributes_t *attributes,
uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
size_t *priv_key_buffer_length,
size_t *pub_key_buffer_length);
/**
* @brief Low level wrapper function to call a driver for an ECC public key export
* of a SECP 192 R1 key.
* See @ref psa_export_public_key()
*
* @param attributes
* @param key_buffer
* @param key_buffer_size
* @param data
* @param data_size
* @param data_length
* @return psa_status_t
*/
psa_status_t psa_ecc_p192r1_export_public_key( const psa_key_attributes_t *attributes,
uint8_t *key_buffer,
size_t key_buffer_size,
uint8_t *data,
size_t data_size,
size_t *data_length);
/**
* @brief Low level wrapper function to call a driver for an ECC hash signature
* with a SECP 192 R1 key.
* See @ref psa_sign_hash()
*
* @param attributes
* @param alg
* @param key_buffer
* @param key_buffer_size
* @param hash
* @param hash_length
* @param signature
* @param signature_size
* @param signature_length
* @return psa_status_t
*/
psa_status_t psa_ecc_p192r1_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const uint8_t *key_buffer, size_t key_buffer_size,
const uint8_t *hash, size_t hash_length,
uint8_t *signature, size_t signature_size,
size_t *signature_length);
/**
* @brief Low level wrapper function to call a driver for an ECC hash verification
* with a SECP 192 R1 key.
* See @ref psa_verify_hash()
*
* @param attributes
* @param alg
* @param key_buffer
* @param key_buffer_size
* @param hash
* @param hash_length
* @param signature
* @param signature_length
* @return psa_status_t
*/
psa_status_t psa_ecc_p192r1_verify_hash(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const uint8_t *key_buffer, size_t key_buffer_size,
const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length);
/**
* @brief Low level wrapper function to call a driver for an ECC key generation
* with a SECP 192 R1 key.
* See @ref psa_generate_key()
*
* @param attributes
* @param priv_key_buffer
* @param pub_key_buffer
* @param priv_key_buffer_length
* @param pub_key_buffer_length
* @return @ref psa_status_t
*/
psa_status_t psa_generate_ecc_p256r1_key_pair( const psa_key_attributes_t *attributes,
uint8_t *priv_key_buffer, uint8_t *pub_key_buffer,
size_t *priv_key_buffer_length,
size_t *pub_key_buffer_length);
/**
* @brief Low level wrapper function to call a driver for an ECC public key export
* of a SECP 256 R1 key.
* See @ref psa_export_public_key()
*
* @param attributes
* @param key_buffer
* @param key_buffer_size
* @param data
* @param data_size
* @param data_length
* @return psa_status_t
*/
psa_status_t psa_ecc_p256r1_export_public_key( const psa_key_attributes_t *attributes,
uint8_t *key_buffer,
size_t key_buffer_size,
uint8_t *data,
size_t data_size,
size_t *data_length);
/**
* @brief Low level wrapper function to call a driver for an ECC hash signature
* with a SECP 256 R1 key.
* See @ref psa_sign_hash()
*
* @param attributes
* @param alg
* @param key_buffer
* @param key_buffer_size
* @param hash
* @param hash_length
* @param signature
* @param signature_size
* @param signature_length
* @return psa_status_t
*/
psa_status_t psa_ecc_p256r1_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const uint8_t *key_buffer, size_t key_buffer_size,
const uint8_t *hash, size_t hash_length,
uint8_t *signature, size_t signature_size,
size_t *signature_length);
/**
* @brief Low level wrapper function to call a driver for an ECC hash verification
* with a SECP 256 R1 key.
* See @ref psa_verify_hash()
*
* @param attributes
* @param alg
* @param key_buffer
* @param key_buffer_size
* @param hash
* @param hash_length
* @param signature
* @param signature_length
* @return psa_status_t
*/
psa_status_t psa_ecc_p256r1_verify_hash(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const uint8_t *key_buffer, size_t key_buffer_size,
const uint8_t *hash, size_t hash_length,
const uint8_t *signature, size_t signature_length);
#ifdef __cplusplus
}
#endif
#endif /* PSA_ECC_H */
/**@}*/

View File

@ -0,0 +1,232 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_hashes PSA Wrapper Functions: Hashes
* @{
*
* @file psa_hashes.h
* @brief Function declarations for low level wrapper functions for hash operations.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_HASHES_H
#define PSA_HASHES_H
#ifdef __cplusplus
extern "C" {
#endif
#include "kernel_defines.h"
#include "psa/crypto.h"
#include "psa/crypto_contexts.h"
#if IS_USED(MODULE_PSA_HASH_MD5) || defined(DOXYGEN)
/**
* @brief Low level wrapper function to call a driver for an MD5 hash setup
* See @ref psa_hash_setup()
*
* @param ctx
* @return @ref psa_status_t
*/
psa_status_t psa_hashes_md5_setup(psa_hashes_md5_ctx_t *ctx);
/**
* @brief Low level wrapper function to call a driver for an MD5 hash update
* See @ref psa_hash_update()
*
* @param ctx
* @param input
* @param input_length
* @return psa_status_t
*/
psa_status_t psa_hashes_md5_update(psa_hashes_md5_ctx_t *ctx,
const uint8_t *input,
size_t input_length);
/**
* @brief Low level wrapper function to call a driver for an MD5 hash finish
* See @ref psa_hash_finish()
*
* @param ctx
* @param hash
* @param hash_size
* @param hash_length
* @return psa_status_t
*/
psa_status_t psa_hashes_md5_finish(psa_hashes_md5_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
#endif /* CONFIG_HASHES_MD5 */
#if IS_USED(MODULE_PSA_HASH_SHA_1) || defined(DOXYGEN)
/**
* @brief Low level wrapper function to call a driver for an SHA1 hash setup
* See @ref psa_hash_setup()
*
* @param ctx
* @return psa_status_t
*/
psa_status_t psa_hashes_sha1_setup(psa_hashes_sha1_ctx_t *ctx);
/**
* @brief Low level wrapper function to call a driver for an SHA1 hash update
* See @ref psa_hash_update()
*
* @param ctx
* @param input
* @param input_length
* @return psa_status_t
*/
psa_status_t psa_hashes_sha1_update(psa_hashes_sha1_ctx_t *ctx,
const uint8_t *input,
size_t input_length);
/**
* @brief Low level wrapper function to call a driver for an SHA1 hash finish
* See @ref psa_hash_finish()
*
* @param ctx
* @param hash
* @param hash_size
* @param hash_length
* @return psa_status_t
*/
psa_status_t psa_hashes_sha1_finish(psa_hashes_sha1_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
#endif /* CONFIG_HASHES_SHA1 */
#if IS_USED(MODULE_PSA_HASH_SHA_224) || defined(DOXYGEN)
/**
* @brief Low level wrapper function to call a driver for an SHA224 hash setup
* See @ref psa_hash_setup()
*
* @param ctx
* @return psa_status_t
*/
psa_status_t psa_hashes_sha224_setup(psa_hashes_sha224_ctx_t *ctx);
/**
* @brief Low level wrapper function to call a driver for an SHA224 hash update
* See @ref psa_hash_update()
*
* @param ctx
* @param input
* @param input_length
* @return psa_status_t
*/
psa_status_t psa_hashes_sha224_update(psa_hashes_sha224_ctx_t *ctx,
const uint8_t *input,
size_t input_length);
/**
* @brief Low level wrapper function to call a driver for an SHA224 hash finish
* See @ref psa_hash_finish()
*
* @param ctx
* @param hash
* @param hash_size
* @param hash_length
* @return psa_status_t
*/
psa_status_t psa_hashes_sha224_finish(psa_hashes_sha224_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
#endif /* CONFIG_HASHES_SHA224 */
#if IS_USED(MODULE_PSA_HASH_SHA_256) || defined(DOXYGEN)
/**
* @brief Low level wrapper function to call a driver for an SHA256 hash setup
* See @ref psa_hash_setup()
*
* @param ctx
* @return psa_status_t
*/
psa_status_t psa_hashes_sha256_setup(psa_hashes_sha256_ctx_t *ctx);
/**
* @brief Low level wrapper function to call a driver for an SHA256 hash update
* See @ref psa_hash_update()
*
* @param ctx
* @param input
* @param input_length
* @return psa_status_t
*/
psa_status_t psa_hashes_sha256_update(psa_hashes_sha256_ctx_t *ctx,
const uint8_t *input,
size_t input_length);
/**
* @brief Low level wrapper function to call a driver for an SHA256 hash finish
* See @ref psa_hash_finish()
*
* @param ctx
* @param hash
* @param hash_size
* @param hash_length
* @return psa_status_t
*/
psa_status_t psa_hashes_sha256_finish(psa_hashes_sha256_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
#endif /* CONFIG_HASHES_SHA256 */
#if IS_USED(MODULE_PSA_HASH_SHA_512) || defined(DOXYGEN)
/**
* @brief Low level wrapper function to call a driver for an SHA512 hash setup
* See @ref psa_hash_setup()
*
* @param ctx
* @return psa_status_t
*/
psa_status_t psa_hashes_sha512_setup(psa_hashes_sha512_ctx_t *ctx);
/**
* @brief Low level wrapper function to call a driver for an SHA512 hash update
* See @ref psa_hash_update()
*
* @param ctx
* @param input
* @param input_length
* @return psa_status_t
*/
psa_status_t psa_hashes_sha512_update(psa_hashes_sha512_ctx_t *ctx,
const uint8_t *input,
size_t input_length);
/**
* @brief Low level wrapper function to call a driver for an SHA512 hash finish
* See @ref psa_hash_finish()
*
* @param ctx
* @param hash
* @param hash_size
* @param hash_length
* @return psa_status_t
*/
psa_status_t psa_hashes_sha512_finish(psa_hashes_sha512_ctx_t *ctx,
uint8_t *hash,
size_t hash_size,
size_t *hash_length);
#endif /* CONFIG_HASHES_SHA512 */
#ifdef __cplusplus
}
#endif
#endif /* PSA_HASHES_H */
/**@}*/

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto
* @defgroup sys_psa_crypto_mac PSA Wrapper Functions: MAC
* @{
*
* @file psa_mac.h
* @brief Function declarations for low level wrapper functions for MAC operations.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
*/
#ifndef PSA_MAC_H
#define PSA_MAC_H
#ifdef __cplusplus
extern "C" {
#endif
#include "kernel_defines.h"
#include "psa/crypto.h"
#include "psa/crypto_contexts.h"
/**
* @brief Low level wrapper function to call a driver for a HMAC SHA256 computation
* See psa_mac_compute()
*
* @param attributes
* @param key_buffer
* @param key_buffer_size
* @param input
* @param input_length
* @param mac
* @param mac_size
* @param mac_length
* @return psa_status_t
*/
psa_status_t psa_mac_compute_hmac_sha256( const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length);
#ifdef __cplusplus
}
#endif
#endif /* PSA_MAC_H */
/**@}*/

1931
sys/psa_crypto/psa_crypto.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,425 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto sys_psa_crypto_alg_disp
* @{
*
* @file
* @brief Dispatch calls from the PSA Crypto API to an available backend.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "kernel_defines.h"
#include "psa/crypto.h"
#include "psa_mac.h"
#include "psa_hashes.h"
#include "psa_ecc.h"
#include "psa_ciphers.h"
#include "psa_crypto_operation_encoder.h"
psa_status_t psa_algorithm_dispatch_hash_setup(psa_hash_operation_t *operation,
psa_algorithm_t alg)
{
psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
switch (alg) {
#if (IS_USED(MODULE_PSA_HASH_MD5))
case PSA_ALG_MD5:
status = psa_hashes_md5_setup(&operation->ctx.md5);
if (status != PSA_SUCCESS) {
return status;
}
break;
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_1))
case PSA_ALG_SHA_1:
status = psa_hashes_sha1_setup(&operation->ctx.sha1);
if (status != PSA_SUCCESS) {
return status;
}
break;
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_224))
case PSA_ALG_SHA_224:
status = psa_hashes_sha224_setup(&operation->ctx.sha224);
if (status != PSA_SUCCESS) {
return status;
}
break;
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_256))
case PSA_ALG_SHA_256:
status = psa_hashes_sha256_setup(&operation->ctx.sha256);
if (status != PSA_SUCCESS) {
return status;
}
break;
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_512))
case PSA_ALG_SHA_512:
status = psa_hashes_sha512_setup(&operation->ctx.sha512);
if (status != PSA_SUCCESS) {
return status;
}
break;
#endif
default:
(void)status;
(void)operation;
return PSA_ERROR_NOT_SUPPORTED;
}
operation->alg = alg;
return PSA_SUCCESS;
}
psa_status_t psa_algorithm_dispatch_hash_update(psa_hash_operation_t *operation,
const uint8_t *input,
size_t input_length)
{
switch (operation->alg) {
#if (IS_USED(MODULE_PSA_HASH_MD5))
case PSA_ALG_MD5:
return psa_hashes_md5_update(&operation->ctx.md5, input, input_length);
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_1))
case PSA_ALG_SHA_1:
return psa_hashes_sha1_update(&operation->ctx.sha1, input, input_length);
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_224))
case PSA_ALG_SHA_224:
return psa_hashes_sha224_update(&operation->ctx.sha224, input, input_length);
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_256))
case PSA_ALG_SHA_256:
return psa_hashes_sha256_update(&operation->ctx.sha256, input, input_length);
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_512))
case PSA_ALG_SHA_512:
return psa_hashes_sha512_update(&operation->ctx.sha512, input, input_length);
#endif
default:
(void)operation;
(void)input;
(void)input_length;
return PSA_ERROR_NOT_SUPPORTED;
}
}
psa_status_t psa_algorithm_dispatch_hash_finish(psa_hash_operation_t *operation,
uint8_t *hash,
size_t hash_size,
size_t *hash_length)
{
switch (operation->alg) {
#if (IS_USED(MODULE_PSA_HASH_MD5))
case PSA_ALG_MD5:
return psa_hashes_md5_finish(&operation->ctx.md5, hash, hash_size, hash_length);
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_1))
case PSA_ALG_SHA_1:
return psa_hashes_sha1_finish(&operation->ctx.sha1, hash, hash_size, hash_length);
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_224))
case PSA_ALG_SHA_224:
return psa_hashes_sha224_finish(&operation->ctx.sha224, hash, hash_size, hash_length);
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_256))
case PSA_ALG_SHA_256:
return psa_hashes_sha256_finish(&operation->ctx.sha256, hash, hash_size, hash_length);
#endif
#if (IS_USED(MODULE_PSA_HASH_SHA_512))
case PSA_ALG_SHA_512:
return psa_hashes_sha512_finish(&operation->ctx.sha512, hash, hash_size, hash_length);
#endif
default:
(void)operation;
(void)hash;
(void)hash_size;
(void)hash_length;
return PSA_ERROR_NOT_SUPPORTED;
}
}
psa_status_t psa_algorithm_dispatch_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length)
{
psa_asym_key_t asym_key = PSA_INVALID_OPERATION;
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type)) {
asym_key =
PSA_ENCODE_ECC_KEY_TYPE(attributes->bits, PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type));
if (asym_key == PSA_INVALID_OPERATION) {
return PSA_ERROR_INVALID_ARGUMENT;
}
}
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
switch (asym_key) {
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)
case PSA_ECC_P192_R1:
return psa_ecc_p192r1_sign_hash(attributes, alg, key_data, *key_bytes, hash, hash_length,
signature, signature_size, signature_length);
#endif
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1)
case PSA_ECC_P256_R1:
return psa_ecc_p256r1_sign_hash(attributes, alg, key_data, *key_bytes, hash, hash_length,
signature, signature_size, signature_length);
#endif
default:
(void)alg;
(void)slot;
(void)hash;
(void)hash_length;
(void)signature;
(void)signature_size;
(void)signature_length;
return PSA_ERROR_NOT_SUPPORTED;
}
}
psa_status_t psa_algorithm_dispatch_verify_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length)
{
psa_asym_key_t asym_key = PSA_INVALID_OPERATION;
uint8_t *pubkey_data = NULL;
size_t *pubkey_data_len = NULL;
if (PSA_KEY_TYPE_IS_ECC(attributes->type)) {
asym_key =
PSA_ENCODE_ECC_KEY_TYPE(attributes->bits, PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type));
if (asym_key == PSA_INVALID_OPERATION) {
return PSA_ERROR_INVALID_ARGUMENT;
}
}
psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
switch (asym_key) {
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)
case PSA_ECC_P192_R1:
return psa_ecc_p192r1_verify_hash(attributes, alg, pubkey_data, *pubkey_data_len, hash,
hash_length, signature, signature_length);
#endif
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1)
case PSA_ECC_P256_R1:
return psa_ecc_p256r1_verify_hash(attributes, alg, pubkey_data, *pubkey_data_len, hash,
hash_length, signature, signature_length);
#endif
default:
(void)alg;
(void)slot;
(void)hash;
(void)hash_length;
(void)signature;
(void)signature_length;
return PSA_ERROR_NOT_SUPPORTED;
}
}
psa_status_t psa_algorithm_dispatch_generate_key( const psa_key_attributes_t *attributes,
psa_key_slot_t *slot)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
/**
* Only asymmetric key generation needs special key generation algorithms. Symmetric keys can
* be created by generating random bytes.
*/
if (PSA_KEY_TYPE_IS_ASYMMETRIC(attributes->type)) {
psa_asym_key_t asym_key = PSA_INVALID_OPERATION;
uint8_t *pubkey_data = NULL;
size_t *pubkey_data_len = NULL;
psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
if (PSA_KEY_TYPE_IS_ECC_KEY_PAIR(attributes->type)) {
asym_key =
PSA_ENCODE_ECC_KEY_TYPE(attributes->bits,
PSA_KEY_TYPE_ECC_GET_CURVE(attributes->type));
if (asym_key == PSA_INVALID_OPERATION) {
return PSA_ERROR_INVALID_ARGUMENT;
}
}
switch (asym_key) {
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P192R1)
case PSA_ECC_P192_R1:
return psa_generate_ecc_p192r1_key_pair(attributes, key_data, pubkey_data, key_bytes,
pubkey_data_len);
#endif
#if IS_USED(MODULE_PSA_ASYMMETRIC_ECC_P256R1)
case PSA_ECC_P256_R1:
return psa_generate_ecc_p256r1_key_pair(attributes, key_data, pubkey_data, key_bytes,
pubkey_data_len);
#endif
default:
(void)status;
(void)slot;
return PSA_ERROR_NOT_SUPPORTED;
}
}
return psa_builtin_generate_key(attributes, key_data, *key_bytes, key_bytes);
}
psa_status_t psa_algorithm_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->bits, attributes->type);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (op == PSA_INVALID_OPERATION) {
return PSA_ERROR_INVALID_ARGUMENT;
}
switch (op) {
#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC)
case PSA_CBC_NO_PAD_AES_128:
return psa_cipher_cbc_aes_128_encrypt(attributes, key_data, *key_bytes, alg, input,
input_length, output, output_size, output_length);
#endif
#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC)
case PSA_CBC_NO_PAD_AES_192:
return psa_cipher_cbc_aes_192_encrypt(attributes, key_data, *key_bytes, alg, input,
input_length, output, output_size, output_length);
#endif
#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC)
case PSA_CBC_NO_PAD_AES_256:
return psa_cipher_cbc_aes_256_encrypt(attributes, key_data, *key_bytes, alg, input,
input_length, output, output_size, output_length);
#endif
default:
(void)slot;
(void)input;
(void)input_length;
(void)output;
(void)output_size;
(void)output_length;
return PSA_ERROR_NOT_SUPPORTED;
}
}
psa_status_t psa_algorithm_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_cipher_op_t op = PSA_ENCODE_CIPHER_OPERATION(alg, attributes->bits, attributes->type);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (op == PSA_INVALID_OPERATION) {
return PSA_ERROR_INVALID_ARGUMENT;
}
switch (op) {
#if IS_USED(MODULE_PSA_CIPHER_AES_128_CBC)
case PSA_CBC_NO_PAD_AES_128:
return psa_cipher_cbc_aes_128_decrypt(attributes, key_data, *key_bytes, alg, input,
input_length, output, output_size, output_length);
#endif
#if IS_USED(MODULE_PSA_CIPHER_AES_192_CBC)
case PSA_CBC_NO_PAD_AES_192:
return psa_cipher_cbc_aes_192_decrypt(attributes, key_data, *key_bytes, alg, input,
input_length, output, output_size, output_length);
#endif
#if IS_USED(MODULE_PSA_CIPHER_AES_256_CBC)
case PSA_CBC_NO_PAD_AES_256:
return psa_cipher_cbc_aes_256_decrypt(attributes, key_data, *key_bytes, alg, input,
input_length, output, output_size, output_length);
#endif
default:
(void)slot;
(void)input;
(void)input_length;
(void)output;
(void)output_size;
(void)output_length;
return PSA_ERROR_NOT_SUPPORTED;
}
}
psa_status_t psa_algorithm_dispatch_mac_compute(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length)
{
psa_status_t status = PSA_ERROR_NOT_SUPPORTED;
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
switch (alg) {
#if IS_USED(MODULE_PSA_MAC_HMAC_SHA_256)
case PSA_ALG_HMAC(PSA_ALG_SHA_256):
status = psa_mac_compute_hmac_sha256(attributes, key_data, *key_bytes, input, input_length,
mac, mac_size, mac_length);
if (status != PSA_SUCCESS) {
return status;
}
break;
#endif
default:
(void)status;
return PSA_ERROR_NOT_SUPPORTED;
}
(void)attributes;
(void)input;
(void)input_length;
(void)mac;
(void)mac_size;
(void)mac_length;
return PSA_SUCCESS;
}

View File

@ -0,0 +1,441 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto sys_psa_crypto_loc_disp
* @{
*
* @file
* @brief Dispatch calls from the PSA Crypto API to an available backend.
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include <stdio.h>
#include "kernel_defines.h"
#include "psa/crypto.h"
#include "psa_crypto_algorithm_dispatch.h"
#include "psa_crypto_slot_management.h"
#include "psa_crypto_se_management.h"
#include "psa_crypto_se_driver.h"
psa_status_t psa_location_dispatch_generate_key(const psa_key_attributes_t *attributes,
psa_key_slot_t *slot)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_status_t status;
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *pubkey_data = NULL;
size_t *pubkey_data_len = NULL;
psa_get_public_key_data_from_key_slot(slot, &pubkey_data, &pubkey_data_len);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->key_management == NULL || drv->key_management->p_generate == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->key_management->p_generate(drv_context, *slot_number, attributes, pubkey_data,
*pubkey_data_len, pubkey_data_len);
if (status != PSA_SUCCESS) {
/* In case anything goes wrong, free the key slot for reuse. */
psa_se_drv_data_t *driver = psa_get_se_driver_data(attributes->lifetime);
psa_status_t abort_status = drv->key_management->p_destroy(drv_context, driver->ctx.internal.persistent_data, *slot_number);
return abort_status == PSA_SUCCESS ? status : abort_status;
}
return PSA_SUCCESS;
}
#endif /* MODULE_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_generate_key(attributes, slot);
}
psa_status_t psa_location_dispatch_import_key( const psa_key_attributes_t *attributes,
const uint8_t *data, size_t data_length,
psa_key_slot_t *slot, size_t *bits)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
size_t key_data_size;
key_data_size = psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->key_management == NULL || drv->key_management->p_import == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
*bits = 0;
status = drv->key_management->p_import(drv_context, *slot_number,
attributes, data,
data_length, bits);
if (status != PSA_SUCCESS) {
/* In case anything goes wrong, free the key slot for reuse. */
psa_se_drv_data_t *driver = psa_get_se_driver_data(attributes->lifetime);
psa_status_t abort_status = drv->key_management->p_destroy(drv_context, driver->ctx.internal.persistent_data, *slot_number);
return abort_status == PSA_SUCCESS ? status : abort_status;
}
return PSA_SUCCESS;
}
#endif /* MODULE_PSA_SECURE_ELEMENT */
switch (location) {
case PSA_KEY_LOCATION_LOCAL_STORAGE:
return psa_builtin_import_key(attributes, data, data_length, key_data, key_data_size, key_bytes, bits);
default:
(void)status;
return PSA_ERROR_NOT_SUPPORTED;
}
}
psa_status_t psa_location_dispatch_cipher_encrypt_setup( psa_cipher_operation_t *operation,
const psa_key_attributes_t *attributes,
const psa_key_slot_t *slot,
psa_algorithm_t alg)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(attributes->lifetime);
if (location != PSA_KEY_LOCATION_LOCAL_STORAGE) {
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->cipher == NULL || drv->cipher->p_setup == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->cipher->p_setup(drv_context, &operation->backend_ctx.se_ctx, *slot_number,
attributes->policy.alg, PSA_CRYPTO_DRIVER_ENCRYPT);
if (status != PSA_SUCCESS) {
return status;
}
return PSA_SUCCESS;
}
}
#endif /* MODULE_PSA_SECURE_ELEMENT */
(void)operation;
(void)attributes;
(void)slot;
(void)alg;
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t psa_location_dispatch_cipher_decrypt_setup(psa_cipher_operation_t *operation,
const psa_key_attributes_t *attributes,
const psa_key_slot_t *slot,
psa_algorithm_t alg)
{
(void)operation;
(void)attributes;
(void)slot;
(void)alg;
return PSA_ERROR_NOT_SUPPORTED;
}
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
/**
* @brief Single part function for cipher encryption and decryption on a secure element
*
* Some secure elements don't provide single part operations for cipher encryption.
* This is a wrapper function, to support those.
*
* @param drv
* @param drv_context
* @param attributes
* @param alg
* @param direction
* @param slot
* @param input
* @param input_length
* @param output
* @param output_size
* @param output_length
* @return @ref psa_status_t
*/
static psa_status_t psa_se_cipher_encrypt_decrypt( const psa_drv_se_t *drv,
psa_drv_se_context_t *drv_context,
const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
psa_encrypt_or_decrypt_t direction,
psa_key_slot_number_t slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
psa_status_t status;
psa_cipher_operation_t operation = psa_cipher_operation_init();
psa_se_cipher_context_t *se_ctx = &operation.backend_ctx.se_ctx;
size_t input_offset = 0;
size_t output_offset = 0;
*output_length = 0;
if (drv->cipher == NULL ||
drv->cipher->p_setup == NULL ||
drv->cipher->p_set_iv == NULL ||
drv->cipher->p_update == NULL ||
drv->cipher->p_finish == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->cipher->p_setup(drv_context, se_ctx, slot, alg, direction);
if (status != PSA_SUCCESS) {
return status;
}
if (alg == PSA_ALG_CBC_NO_PADDING) {
operation.iv_required = 1;
operation.default_iv_length = PSA_CIPHER_IV_LENGTH(psa_get_key_type(attributes), alg);
if (direction == PSA_CRYPTO_DRIVER_ENCRYPT) {
/* In case of encryption, we need to generate and set an IV. The IV will be written
into the first 16 bytes of the output buffer. */
size_t iv_length = 0;
status = psa_cipher_generate_iv(&operation, output, operation.default_iv_length,
&iv_length);
status = drv->cipher->p_set_iv(se_ctx, output, iv_length);
if (status != PSA_SUCCESS) {
return status;
}
/* Increase output buffer offset to IV length to write ciphertext to buffer after IV */
output_offset += iv_length;
*output_length += iv_length;
}
else {
/* In case of decryption the IV to be used must be provided by the caller and is
contained in the first 16 Bytes of the input buffer. */
status = drv->cipher->p_set_iv(se_ctx, input, operation.default_iv_length);
/* Increase input buffer offset to IV length to start decryption
with actual cipher text */
input_offset += operation.default_iv_length;
}
}
status = drv->cipher->p_update(se_ctx, input + input_offset, input_length - input_offset,
output + output_offset, output_size - output_offset,
output_length);
if (status != PSA_SUCCESS) {
psa_cipher_abort(&operation);
return status;
}
status = drv->cipher->p_finish(se_ctx, output, output_size, output_length);
if (status != PSA_SUCCESS) {
return status;
}
return PSA_SUCCESS;
}
#endif /* CONFIG_PSA_SECURE_ELEMENT */
psa_status_t psa_location_dispatch_cipher_encrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (alg == PSA_ALG_ECB_NO_PADDING) {
if (drv->cipher == NULL || drv->cipher->p_ecb == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->cipher->p_ecb(drv_context, *slot_number, alg, PSA_CRYPTO_DRIVER_ENCRYPT,
input, input_length, output, output_size);
if (status != PSA_SUCCESS) {
return status;
}
}
/* The SE interface does not support single part functions for other algorithms than ECB,
so we need to build one ourselves */
status = psa_se_cipher_encrypt_decrypt(drv, drv_context, attributes, alg,
PSA_CRYPTO_DRIVER_ENCRYPT, *slot_number, input,
input_length, output, output_size, output_length);
return status;
}
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_cipher_encrypt(attributes, alg, slot, input, input_length, output,
output_size, output_length);
}
psa_status_t psa_location_dispatch_cipher_decrypt( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *output,
size_t output_size,
size_t *output_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (alg == PSA_ALG_ECB_NO_PADDING) {
if (drv->cipher == NULL || drv->cipher->p_ecb == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = drv->cipher->p_ecb(drv_context, *slot_number, alg, PSA_CRYPTO_DRIVER_DECRYPT,
input, input_length, output, output_size);
if (status != PSA_SUCCESS) {
return status;
}
}
status = psa_se_cipher_encrypt_decrypt(drv, drv_context, attributes, alg,
PSA_CRYPTO_DRIVER_DECRYPT, *slot_number, input,
input_length, output, output_size, output_length);
return status;
}
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_cipher_decrypt(attributes, alg, slot, input, input_length,
output, output_size, output_length);
}
psa_status_t psa_location_dispatch_sign_hash( const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
uint8_t *signature,
size_t signature_size,
size_t *signature_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->asymmetric == NULL || drv->asymmetric->p_sign == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
return drv->asymmetric->p_sign(drv_context, *slot_number, alg, hash, hash_length, signature,
signature_size, signature_length);
}
(void)key_bytes;
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_sign_hash(attributes, alg, slot, hash, hash_length, signature,
signature_size, signature_length);
}
psa_status_t psa_location_dispatch_verify_hash(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *hash,
size_t hash_length,
const uint8_t *signature,
size_t signature_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->asymmetric == NULL || drv->asymmetric->p_verify == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
return drv->asymmetric->p_verify(drv_context, *slot_number, alg, hash, hash_length,
signature, signature_length);
}
(void)key_bytes;
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_verify_hash(attributes, alg, slot, hash, hash_length, signature,
signature_length);
}
psa_status_t psa_location_dispatch_mac_compute(const psa_key_attributes_t *attributes,
psa_algorithm_t alg,
const psa_key_slot_t *slot,
const uint8_t *input,
size_t input_length,
uint8_t *mac,
size_t mac_size,
size_t *mac_length)
{
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
const psa_drv_se_t *drv;
psa_drv_se_context_t *drv_context;
psa_key_slot_number_t *slot_number = psa_key_slot_get_slot_number(slot);
uint8_t *key_data = NULL;
size_t *key_bytes = NULL;
psa_get_key_data_from_key_slot(slot, &key_data, &key_bytes);
if (psa_get_se_driver(attributes->lifetime, &drv, &drv_context)) {
if (drv->mac == NULL || drv->mac->p_mac == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
return drv->mac->p_mac(drv_context, input, input_length, *slot_number, alg, mac, mac_size,
mac_length);
}
(void)key_bytes;
#endif /* CONFIG_PSA_SECURE_ELEMENT */
return psa_algorithm_dispatch_mac_compute(attributes, alg, slot, input, input_length, mac,
mac_size, mac_length);
}
psa_status_t psa_location_dispatch_generate_random(uint8_t *output,
size_t output_size)
{
return psa_builtin_generate_random(output, output_size);
}

View File

@ -0,0 +1,10 @@
# Copyright (c) 2022 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
config MODULE_PSA_KEY_SLOT_MGMT
bool
default y if PACKAGE_PSA_ARCH_TESTS

View File

@ -0,0 +1,4 @@
MODULE := psa_key_slot_mgmt
INCLUDES += -I$(RIOTBASE)/sys/psa_crypto/include
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,539 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto sys_psa_crypto_slot_mgmt
* @{
*
* @file
* @brief PSA Crypto Key Slot Management implementation
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "clist.h"
#include "psa_crypto_slot_management.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
/**
* @brief Structure for a protected key slot.
*
* These slots hold Slot Numbers for keys in protected storage and, if the key type is an
* asymmetric key pair, the public key.
*/
typedef struct {
clist_node_t node;
size_t lock_count;
psa_key_attributes_t attr;
struct prot_key_data {
psa_key_slot_number_t slot_number;
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC)
uint8_t pubkey_data[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
size_t pubkey_data_len;
#endif
} key;
} psa_prot_key_slot_t;
/**
* @brief Array containing the protected key slots
*/
static psa_prot_key_slot_t protected_key_slots[PSA_PROTECTED_KEY_COUNT];
/**
* @brief List pointing to empty protected key slots
*/
static clist_node_t protected_list_empty;
#endif /* MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC */
#if IS_USED(MODULE_PSA_ASYMMETRIC)
/**
* @brief Structure for asymmetric key pairs.
*
* Contains asymmetric private and public key pairs.
*
*/
typedef struct {
clist_node_t node;
size_t lock_count;
psa_key_attributes_t attr;
struct key_pair_data {
/** Contains asymmetric private key*/
uint8_t privkey_data[PSA_BITS_TO_BYTES(PSA_MAX_PRIV_KEY_SIZE)];
/** Contains actual size of asymmetric private key */
size_t privkey_data_len;
/** Contains asymmetric public key */
uint8_t pubkey_data[PSA_EXPORT_PUBLIC_KEY_MAX_SIZE];
/*!< Contains actual size of asymmetric private key */
size_t pubkey_data_len;
} key;
} psa_key_pair_slot_t;
/**
* @brief Array containing the asymmetric key slots
*/
static psa_key_pair_slot_t key_pair_slots[PSA_ASYMMETRIC_KEYPAIR_COUNT];
/**
* @brief List pointing to empty asymmetric key slots
*/
static clist_node_t key_pair_list_empty;
#endif /* MODULE_PSA_ASYMMETRIC */
/**
* @brief Array containing the single key slots
*/
static psa_key_slot_t single_key_slots[PSA_SINGLE_KEY_COUNT];
/**
* @brief List pointing to empty single key slots
*/
static clist_node_t single_key_list_empty;
/**
* @brief Global list of used key slots
*/
static clist_node_t key_slot_list;
/**
* @brief Counter for volatile key IDs.
*/
static psa_key_id_t key_id_count = PSA_KEY_ID_VOLATILE_MIN;
/**
* @brief Get the correct empty slot list, depending on the key type
*
* @param attr
* @return clist_node_t* Pointer to the list the key is supposed to be stored in,
* according to its attributes
*/
static clist_node_t * psa_get_empty_key_slot_list(const psa_key_attributes_t *attr)
{
if (!psa_key_lifetime_is_external(attr->lifetime)) {
#if IS_USED(MODULE_PSA_ASYMMETRIC)
if (PSA_KEY_TYPE_IS_KEY_PAIR(attr->type)) {
return &key_pair_list_empty;
}
#endif /* MODULE_PSA_ASYMMETRIC */
return &single_key_list_empty;
}
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
return &protected_list_empty;
#else
return NULL;
#endif /* MODULE_PSA_SECURE_ELEMENT */
}
void psa_init_key_slots(void)
{
DEBUG("List Node Size: %d\n", sizeof(clist_node_t));
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
memset(protected_key_slots, 0, sizeof(protected_key_slots));
#if PSA_PROTECTED_KEY_COUNT
for (size_t i = 0; i < PSA_PROTECTED_KEY_COUNT; i++) {
clist_rpush(&protected_list_empty, &protected_key_slots[i].node);
}
#endif /* PSA_PROTECTED_KEY_COUNT */
DEBUG("Protected Slot Count: %d, Size: %d\n", PSA_PROTECTED_KEY_COUNT,
sizeof(psa_prot_key_slot_t));
DEBUG("Protected Slot Array Size: %d\n", sizeof(protected_key_slots));
DEBUG("Protected Slot Empty List Size: %d\n", clist_count(&protected_list_empty));
#endif /* MODULE_PSA_SECURE_ELEMENT */
#if IS_USED(MODULE_PSA_ASYMMETRIC)
memset(key_pair_slots, 0, sizeof(key_pair_slots));
#if PSA_ASYMMETRIC_KEYPAIR_COUNT
for (size_t i = 0; i < PSA_ASYMMETRIC_KEYPAIR_COUNT; i++) {
clist_rpush(&key_pair_list_empty, &key_pair_slots[i].node);
}
#endif /* PSA_ASYMMETRIC_KEYPAIR_COUNT */
DEBUG("Asymmetric Slot Count: %d, Size: %d\n", PSA_ASYMMETRIC_KEYPAIR_COUNT,
sizeof(psa_key_pair_slot_t));
DEBUG("Asymmetric Slot Array Size: %d\n", sizeof(key_pair_slots));
DEBUG("Asymmetric Slot Empty List Size: %d\n", clist_count(&key_pair_list_empty));
#endif /* MODULE_PSA_ASYMMETRIC */
memset(single_key_slots, 0, sizeof(single_key_slots));
#if PSA_SINGLE_KEY_COUNT
for (size_t i = 0; i < PSA_SINGLE_KEY_COUNT; i++) {
clist_rpush(&single_key_list_empty, &single_key_slots[i].node);
}
#endif
DEBUG("Single Key Slot Count: %d, Size: %d\n", PSA_SINGLE_KEY_COUNT, sizeof(psa_key_slot_t));
DEBUG("Single Key Slot Array Size: %d\n", sizeof(single_key_slots));
DEBUG("Single Key Slot Empty List Size: %d\n", clist_count(&single_key_list_empty));
}
/**
* @brief Wipe key slot with correct key slot size
*
* @param slot Key sloit to be wiped
*/
static void psa_wipe_real_slot_type(psa_key_slot_t *slot)
{
psa_key_attributes_t attr = slot->attr;
if (!psa_key_lifetime_is_external(attr.lifetime)) {
if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) {
memset(slot, 0, sizeof(psa_key_slot_t));
}
#if IS_USED(MODULE_PSA_ASYMMETRIC)
else {
memset((psa_key_pair_slot_t *)slot, 0, sizeof(psa_key_pair_slot_t));
}
#endif
}
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
else {
memset((psa_prot_key_slot_t *)slot, 0, sizeof(psa_prot_key_slot_t));
}
#endif
}
psa_status_t psa_wipe_key_slot(psa_key_slot_t *slot)
{
/* Get list the slot is stored in */
clist_node_t *empty_list = psa_get_empty_key_slot_list(&slot->attr);
if (empty_list == NULL) {
return PSA_ERROR_DOES_NOT_EXIST;
}
/* Get node to remove from key slot list */
clist_node_t *n = clist_remove(&key_slot_list, &slot->node);
if (n == NULL) {
return PSA_ERROR_DOES_NOT_EXIST;
}
psa_key_slot_t *tmp = container_of(n, psa_key_slot_t, node);
/* Wipe slot associated with node */
psa_wipe_real_slot_type(tmp);
/* Append node to empty list for later reuse */
clist_rpush(empty_list, n);
return PSA_SUCCESS;
}
void psa_wipe_all_key_slots(void)
{
/* Move all list items to empty lists */
while (!clist_is_empty(&key_slot_list)) {
clist_node_t *to_remove = clist_rpop(&key_slot_list);
psa_key_slot_t *slot = container_of(to_remove, psa_key_slot_t, node);
clist_node_t *empty_list = psa_get_empty_key_slot_list(&slot->attr);
psa_wipe_real_slot_type(slot);
clist_rpush(empty_list, to_remove);
}
}
/**
* @brief Check whether a given key ID equals the ID of the given node.
*
* This is the break condition of the @ref clist_foreach function used
* in @ref psa_get_and_lock_key_slot_in_memory.
* clist_foreach iterates over all key slots and calls this function
* to compare each slot's key ID to the given input key ID.
* If they are equal, this function returns True and breaks the foreach
* loop.
*
* For more information see core/lib/include/clist.h.
*
* @param n Pointer to clist node referencing a key slot
* @param arg Pointer to required key ID
* @return int
* 1 if input ID equals node ID
* 0 otherwise
*/
static int node_id_equals_key_id(clist_node_t *n, void *arg)
{
psa_key_slot_t *slot = container_of(n, psa_key_slot_t, node);
psa_key_id_t id = *((psa_key_id_t *)arg);
if (slot->attr.id == id) {
return 1;
}
return 0;
}
/**
* @brief Find the key slot containing the key with a specified ID
*
* @param id ID of the required key
* @param p_slot Pointer to the slot that will contain the required key
*
* @return @ref PSA_SUCCESS
* @ref PSA_ERROR_INVALID_HANDLE
* @ref PSA_ERROR_CORRUPTION_DETECTED
* @ref PSA_ERROR_NOT_SUPPORTED
*/
static psa_status_t psa_get_and_lock_key_slot_in_memory(psa_key_id_t id, psa_key_slot_t **p_slot)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
if (psa_key_id_is_volatile(id)) {
clist_node_t *slot_node = clist_foreach(&key_slot_list, node_id_equals_key_id, &id);
if (slot_node == NULL) {
return PSA_ERROR_INVALID_HANDLE;
}
psa_key_slot_t *slot = container_of(slot_node, psa_key_slot_t, node);
status = psa_lock_key_slot(slot);
if (status == PSA_SUCCESS) {
*p_slot = slot;
}
return status;
}
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t psa_get_and_lock_key_slot(psa_key_id_t id, psa_key_slot_t **p_slot)
{
/* TODO validate ID */
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
*p_slot = NULL;
status = psa_get_and_lock_key_slot_in_memory(id, p_slot);
if (status != PSA_ERROR_DOES_NOT_EXIST) {
return status;
}
/* TODO: get persistent key from storage and load into slot */
return status;
}
/**
* @brief Allocate a free slot for a new key creation
*
* @param p_slot Pointer that will contain the free key slot.
* @param attr Attributes of type @ref psa_key_attrubutes_t for the key to be created
*
* @return @ref PSA_SUCCESS
* @ref PSA_ERROR_DOES_NOT_EXIST No key slots for this type of key exist
* @ref PSA_ERROR_INSUFFICIENT_STORAGE
*/
static psa_status_t psa_allocate_key_slot_in_list(psa_key_slot_t **p_slot,
const psa_key_attributes_t *attr)
{
clist_node_t *empty_list = psa_get_empty_key_slot_list(attr);
if (empty_list == NULL) {
return PSA_ERROR_DOES_NOT_EXIST;
}
/* Check if any empty elements of this key slot type are left */
if (clist_is_empty(empty_list)) {
DEBUG("Key Slot MGMT: No PSA Key Slot available\n");
return PSA_ERROR_INSUFFICIENT_STORAGE;
}
/* TODO: If no slots left: Look for slot in list with persistent key
(key will be stored in persistent memory and slot can be reused) */
/* Remove key slote node from empty list and append to actual list */
clist_node_t *new_slot = clist_rpop(empty_list);
clist_rpush(&key_slot_list, new_slot);
psa_key_slot_t *slot = container_of(new_slot, psa_key_slot_t, node);
*p_slot = slot;
return PSA_SUCCESS;
}
psa_status_t psa_allocate_empty_key_slot( psa_key_id_t *id,
const psa_key_attributes_t *attr,
psa_key_slot_t **p_slot)
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *new_slot = NULL;
/* Change later, when we also have persistent keys */
if (key_id_count == PSA_KEY_ID_VOLATILE_MAX) {
DEBUG("Key Slot MGMT: Maximum key ID reached\n");
return PSA_ERROR_INSUFFICIENT_STORAGE;
}
status = psa_allocate_key_slot_in_list(&new_slot, attr);
if (status != PSA_SUCCESS) {
*p_slot = NULL;
*id = 0;
return status;
}
if (new_slot != NULL) {
status = psa_lock_key_slot(new_slot);
if (status != PSA_SUCCESS) {
*p_slot = NULL;
*id = 0;
return status;
}
*id = key_id_count++;
*p_slot = new_slot;
return PSA_SUCCESS;
}
status = PSA_ERROR_INSUFFICIENT_MEMORY;
*p_slot = NULL;
*id = 0;
return status;
}
psa_status_t psa_lock_key_slot(psa_key_slot_t *slot)
{
if (slot->lock_count >= SIZE_MAX) {
return PSA_ERROR_CORRUPTION_DETECTED;
}
slot->lock_count++;
return PSA_SUCCESS;
}
psa_status_t psa_unlock_key_slot(psa_key_slot_t *slot)
{
if (slot == NULL) {
return PSA_SUCCESS;
}
if (slot->lock_count > 0) {
slot->lock_count--;
return PSA_SUCCESS;
}
return PSA_ERROR_CORRUPTION_DETECTED;
}
psa_status_t psa_validate_key_location(psa_key_lifetime_t lifetime, psa_se_drv_data_t **p_drv)
{
if (psa_key_lifetime_is_external(lifetime)) {
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_se_drv_data_t *driver = psa_get_se_driver_data(lifetime);
if (driver != NULL) {
if (p_drv != NULL) {
*p_drv = driver;
}
return PSA_SUCCESS;
}
#else
(void)p_drv;
#endif /* MODULE_PSA_SECURE_ELEMENT */
return PSA_ERROR_INVALID_ARGUMENT;
}
else {
(void)p_drv;
return PSA_SUCCESS;
}
}
psa_status_t psa_validate_key_persistence(psa_key_lifetime_t lifetime)
{
if (PSA_KEY_LIFETIME_IS_VOLATILE(lifetime)) {
return PSA_SUCCESS;
}
/* TODO: Implement persistent key storage */
return PSA_ERROR_NOT_SUPPORTED;
}
int psa_is_valid_key_id(psa_key_id_t id, int vendor)
{
if ((PSA_KEY_ID_USER_MIN <= id) &&
(id <= PSA_KEY_ID_USER_MAX)) {
return 1;
}
if (vendor
&& (PSA_KEY_ID_VENDOR_MIN <= id)
&& (id <= PSA_KEY_ID_VENDOR_MAX)) {
return 1;
}
return 0;
}
size_t psa_get_key_data_from_key_slot(const psa_key_slot_t *slot, uint8_t **key_data,
size_t **key_bytes)
{
psa_key_attributes_t attr = slot->attr;
size_t key_data_size = 0;
*key_data = NULL;
*key_bytes = NULL;
if (!psa_key_lifetime_is_external(attr.lifetime)) {
if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) {
*key_data = (uint8_t *)slot->key.data;
*key_bytes = (size_t *)&slot->key.data_len;
key_data_size = sizeof(slot->key.data);
}
#if IS_USED(MODULE_PSA_ASYMMETRIC)
else {
*key_data = ((psa_key_pair_slot_t *)slot)->key.privkey_data;
*key_bytes = &((psa_key_pair_slot_t *)slot)->key.privkey_data_len;
key_data_size = sizeof(((psa_key_pair_slot_t *)slot)->key.privkey_data);
}
#endif
}
return key_data_size;
}
#if IS_USED(MODULE_PSA_SECURE_ELEMENT)
psa_key_slot_number_t * psa_key_slot_get_slot_number(const psa_key_slot_t *slot)
{
return &(((psa_prot_key_slot_t *)slot)->key.slot_number);
}
#endif
void psa_get_public_key_data_from_key_slot(const psa_key_slot_t *slot, uint8_t **pubkey_data,
size_t **pubkey_data_len)
{
psa_key_attributes_t attr = slot->attr;
/* If key type is not asymmetric, no public key exists */
if (!PSA_KEY_TYPE_IS_ASYMMETRIC(attr.type)) {
*pubkey_data = NULL;
*pubkey_data_len = NULL;
return;
}
if (!psa_key_lifetime_is_external(attr.lifetime)) {
if (!PSA_KEY_TYPE_IS_KEY_PAIR(attr.type)) {
*pubkey_data = ((psa_key_slot_t *)slot)->key.data;
*pubkey_data_len = &((psa_key_slot_t *)slot)->key.data_len;
return;
}
#if IS_USED(MODULE_PSA_ASYMMETRIC)
else {
*pubkey_data = ((psa_key_pair_slot_t *)slot)->key.pubkey_data;
*pubkey_data_len = &((psa_key_pair_slot_t *)slot)->key.pubkey_data_len;
return;
}
#endif
}
#if IS_USED(MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC)
*pubkey_data = ((psa_prot_key_slot_t *)slot)->key.pubkey_data;
*pubkey_data_len = &((psa_prot_key_slot_t *)slot)->key.pubkey_data_len;
#endif
}

View File

@ -0,0 +1,53 @@
# Copyright (c) 2022 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menuconfig MODULE_PSA_SECURE_ELEMENT
bool "PSA Secure Elements"
select MODULE_PSA_KEY_SLOT_MGMT
select MODULE_PSA_SE_MGMT
if MODULE_PSA_SECURE_ELEMENT
config MODULE_PSA_SECURE_ELEMENT_MULTIPLE
bool "Use multiple secure elements"
config PSA_MAX_SE_COUNT
int
prompt "Maximum number of secure elements" if MODULE_PSA_SECURE_ELEMENT_MULTIPLE
range 2 255 if MODULE_PSA_SECURE_ELEMENT_MULTIPLE
range 1 255
menuconfig MODULE_PSA_SECURE_ELEMENT_ATECCX08A
bool "Microchip ATECCX08A"
select PACKAGE_CRYPTOAUTHLIB
select MODULE_PSA_SECURE_ELEMENT_CONFIG
depends on HAS_PERIPH_I2C
help
When using Cryptoauthlib as a backend for elliptic curve operations,
please also choose the ECC symbol.
config MODULE_PSA_SECURE_ELEMENT_ATECCX08A_ECC_P256
bool "Microchip ATECCX08A Elliptic Curve P256"
select PSA_KEY_SIZE_256
select MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC
depends on MODULE_PSA_SECURE_ELEMENT_ATECCX08A
config MODULE_PSA_SE_MGMT
bool
config MODULE_PSA_SECURE_ELEMENT_ASYMMETRIC
bool
help
Indicates that an asymmetric operation is used with secure elements.
config MODULE_PSA_SECURE_ELEMENT_CONFIG
bool
help
Indicates that this SE driver defines a configuration structure for
persistent driver data.
endif # MODULE_PSA_SECURE_ELEMENT

View File

@ -0,0 +1,3 @@
MODULE := psa_se_mgmt
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1,193 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_psa_crypto psa_crypto_se_mgmt
* @{
*
* @brief PSA Crypto Secure Element Management implementation
*
* @author Lena Boeckmann <lena.boeckmann@haw-hamburg.de>
*
* @}
*/
#include "psa_crypto_se_management.h"
#include "psa_crypto_se_driver.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/**
* @brief Array containing the registered driver instances.
*/
static psa_se_drv_data_t driver_table[PSA_MAX_SE_COUNT];
/**
* @brief Global counter for registered SE devices.
*/
unsigned psa_se_count = 0;
psa_status_t psa_register_secure_element(psa_key_location_t location,
const psa_drv_se_t *methods,
void *psa_se_configuration,
const void *drv_transient_data)
{
size_t i;
psa_se_drv_data_t *temp;
if (psa_se_count >= PSA_MAX_SE_COUNT) {
DEBUG("SE Registration: Maximum number of Secure Elements reached.\n");
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
if (methods->hal_version != PSA_DRV_SE_HAL_VERSION) {
DEBUG("SE Registration: Driver HAL Version not supported.\n");
return PSA_ERROR_NOT_SUPPORTED;
}
if (location == PSA_KEY_LOCATION_LOCAL_STORAGE) {
DEBUG("SE Registration: Invalid driver location value.\n");
return PSA_ERROR_INVALID_ARGUMENT;
}
if (location > PSA_KEY_LOCATION_SE_MAX) {
DEBUG("SE Registration: Exhausted maximum number of Secure Element location values.\n");
return PSA_ERROR_INVALID_ARGUMENT;
}
if (methods->persistent_data_size > PSA_MAX_PERSISTENT_DATA_SIZE) {
DEBUG("SE Registration: Persistent Data is too large.\n");
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
/* Find next free slot in driver table */
for (i = 0; i < psa_se_count; i++) {
if (driver_table[i].location == location) {
DEBUG("SE Registration: Device with location 0x%x already exists.\n", (int)location);
return PSA_ERROR_ALREADY_EXISTS;
}
if (driver_table[i].location == 0) {
break;
}
}
temp = &driver_table[i];
temp->location = location;
temp->methods = methods;
temp->ctx.internal.transient_data = (uintptr_t)drv_transient_data;
temp->ctx.internal.persistent_data = psa_se_configuration;
temp->ctx.internal.persistent_data_size = methods->persistent_data_size;
/* TODO: Load Persistent data if persistent_data_size != 0 */
psa_se_count++;
return PSA_SUCCESS;
}
psa_se_drv_data_t *psa_get_se_driver_data(psa_key_lifetime_t lifetime)
{
psa_se_drv_data_t *drv = NULL;
psa_key_location_t location = PSA_KEY_LIFETIME_GET_LOCATION(lifetime);
if (location == 0) {
return NULL;
}
for (size_t i = 0; i < PSA_MAX_SE_COUNT; i++) {
if (driver_table[i].location == location) {
drv = &driver_table[i];
}
}
(void)lifetime;
return drv;
}
int psa_get_se_driver(psa_key_lifetime_t lifetime,
const psa_drv_se_t **p_methods,
psa_drv_se_context_t **p_drv_context)
{
psa_se_drv_data_t *driver = psa_get_se_driver_data(lifetime);
if (p_methods != NULL) {
*p_methods = (driver ? driver->methods : NULL);
}
if (p_drv_context != NULL) {
*p_drv_context = (driver ? &driver->ctx.context : NULL);
}
return (driver != NULL);
}
const psa_drv_se_t *psa_get_se_driver_methods(const psa_se_drv_data_t *driver)
{
return driver->methods;
}
psa_drv_se_context_t *psa_get_se_drv_context(psa_se_drv_data_t *driver)
{
return &driver->ctx.context;
}
psa_status_t psa_find_free_se_slot(const psa_key_attributes_t *attributes,
psa_key_creation_method_t method,
psa_se_drv_data_t *driver,
psa_key_slot_number_t *slot_number)
{
psa_status_t status;
psa_key_location_t key_location =
PSA_KEY_LIFETIME_GET_LOCATION(psa_get_key_lifetime(attributes));
if (driver->location != key_location) {
return PSA_ERROR_CORRUPTION_DETECTED;
}
if (driver->methods->key_management == NULL ||
driver->methods->key_management->p_allocate == NULL) {
return PSA_ERROR_NOT_SUPPORTED;
}
status = driver->methods->key_management->p_allocate(&driver->ctx.context,
driver->ctx.internal.persistent_data,
attributes, method, slot_number);
return status;
}
psa_status_t psa_destroy_se_key(psa_se_drv_data_t *driver,
psa_key_slot_number_t slot_number)
{
if (driver->methods->key_management == NULL ||
driver->methods->key_management->p_destroy == NULL) {
return PSA_ERROR_NOT_PERMITTED;
}
return driver->methods->key_management->p_destroy(&driver->ctx.context,
driver->ctx.internal.persistent_data,
slot_number);
/* TODO: Store Persistent Data */
}
psa_status_t psa_load_se_persistent_data(const psa_se_drv_data_t *driver)
{
(void)driver;
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t psa_save_se_persistent_data(const psa_se_drv_data_t *driver)
{
(void)driver;
return PSA_ERROR_NOT_SUPPORTED;
}
psa_status_t psa_destroy_se_persistent_data(psa_key_location_t location)
{
(void)location;
return PSA_ERROR_NOT_SUPPORTED;
}