27#define RESPONSE_GETCARDCERTIFICATE_IN_BYTES 148U
29#define RESPONSE_SELECT_IN_BYTES 40U
31#define RESPONSE_GETMANUFACTURERCERT_PAGE_IN_BYTES 420U
32#define RESPONSE_OPENSECURECHANNEL_IN_BYTES 34U
33#define REQUEST_MUTUALLYAUTHENTICATE_IN_BYTES 69U
34#define RESPONSE_MUTUALLYAUTHENTICATE_IN_BYTES 66U
35#define RESPONSE_STATUS_WORDS_IN_BYTES 2U
37#define OPENSECURECHANNEL_SALT_IN_BYTES (RESPONSE_OPENSECURECHANNEL_IN_BYTES - RESPONSE_STATUS_WORDS_IN_BYTES)
38#define GETCARDCERTIFICATE_IN_BYTES (RESPONSE_GETCARDCERTIFICATE_IN_BYTES - RESPONSE_STATUS_WORDS_IN_BYTES)
40#define RANDOM_BYTES 8U
41#define COMMON_PAIRING_DATA CW_PAIRING_DATA
42#define CLIENT_PRIVATE_KEY_SIZE 32U
43#define CLIENT_PUBLIC_KEY_SIZE 64U
44#define CARDEPHEMERALPUBKEY_SIZE 64U
45#define AES_BLOCK_SIZE 16U
46#define APDU_HEADER_LEN (4U)
47#define APDU_LC_LEN (1U)
48#define MAC_APDU_LEN (12U)
49#define INPUT_BUFFER_LIMIT (CW_USER_DATA_PAGE_SIZE)
50#define ENC_BUF_MAX_LEN (INPUT_BUFFER_LIMIT + AES_BLOCK_SIZE)
51#define MAX_MAC_DATA_LEN (APDU_HEADER_LEN + MAC_APDU_LEN + ENC_BUF_MAX_LEN)
52#define SEND_APDU_MAX_LEN (APDU_HEADER_LEN + APDU_LC_LEN + AES_BLOCK_SIZE + ENC_BUF_MAX_LEN)
56 "CW_USER_DATA_PAGE_SIZE too large for PN532 single APDU transport");
68#define DER_TAG_SEQUENCE (0x30U)
69#define DER_TAG_BIT_STRING (0x03U)
70#define DER_TAG_CTX0 (0xA0U)
73#define DER_LEN_LONG_FLAG (0x80U)
74#define DER_LEN_LONG_1 (0x81U)
75#define DER_LEN_LONG_2 (0x82U)
78#define DER_EC_UNCOMPRESSED (0x04U)
79#define DER_EC_POINT_BYTES (65U)
80#define DER_BIT_UNUSED_ZERO (0x00U)
105 return _driver.inListPassiveTarget();
113 return _driver.printFirmwareVersion();
121 uint8_t sw1Expected, uint8_t sw2Expected) {
124 if ((response == NULL) || (responseLength < 2U)) {
126 _logger.println(
F(
"checkStatusWord: response too short."));
130 uint8_t sw1 = response[responseLength - 2U];
131 uint8_t sw2 = response[responseLength - 1U];
133 if ((sw1 == sw1Expected) && (sw2 == sw2Expected)) {
139 if (sw1 < 16U) {
_logger.print(
F(
"0")); }
142 if (sw2 < 16U) {
_logger.print(
F(
"0")); }
158 uint8_t selectApduCmd[] = {
159 0x00, 0xA4, 0x04, 0x00,
161 0xA0, 0x00, 0x00, 0x10, 0x00, 0x01, 0x12
165 uint8_t responseLength =
static_cast<uint8_t
>(
sizeof(response));
167 if (
_driver.sendAPDU(selectApduCmd,
sizeof(selectApduCmd), response, responseLength)) {
172 _logger.println(
F(
"Select APDU failed."));
177 _logger.println(
F(
"APDU select failed."));
187 uint8_t getCardCertificateResponseLength =
static_cast<uint8_t
>(
sizeof(getCardCertificateResponse));
189 if (cardCertificate != NULL) {
193 _logger.println(
F(
"getCardCertificate: RNG failed."));
201 uint8_t getCardCertificateApdu[] = {
202 0x80, 0xF8, 0x00, 0x00, 0x08
205 uint8_t fullApdu[
sizeof(getCardCertificateApdu) +
RANDOM_BYTES];
206 (void)
CW_Utils::safe_memcpy(fullApdu,
sizeof(fullApdu), getCardCertificateApdu,
sizeof(getCardCertificateApdu));
209 if (
_driver.sendAPDU(fullApdu,
sizeof(fullApdu),
210 getCardCertificateResponse, getCardCertificateResponseLength)) {
211 if (
checkStatusWord(getCardCertificateResponse, getCardCertificateResponseLength,
213 cardCertificateLength =
static_cast<uint8_t
>(
219 _logger.println(
F(
"getCardCertificate: bad SW."));
224 _logger.println(
F(
"getCardCertificate APDU failed."));
233 uint8_t* cardEphemeralPubKey,
234 uint8_t* fullEphemeralPubKey65) {
237 if ((cardCertificate == NULL) || (cardEphemeralPubKey == NULL)) {
241 const uint8_t keyStart = 1U + 8U;
242 const uint8_t fullKeyLength = 65U;
245 if (cardCertificate[keyStart] != 0x04U) {
249 for (uint8_t i = 0U; i < fullKeyLength; i++) {
250 uint8_t b = cardCertificate[keyStart + i];
251 if (fullEphemeralPubKey65 != NULL) {
252 fullEphemeralPubKey65[i] = b;
255 cardEphemeralPubKey[i - 1U] = b;
266 uint8_t* sessionPublicKey,
267 uint8_t* sessionPrivateKey,
271 if (!
_crypto.makeKey(sessionPublicKey, sessionPrivateKey, sessionCurve)) {
273 _logger.println(
F(
"ECC key generation failed."));
277 uint8_t opcApduHeader[] = {
278 0x80, 0x10, 0x00, 0x00, 0x41, 0x04
286 uint8_t responseLength =
static_cast<uint8_t
>(
sizeof(response));
288 if (
_driver.sendAPDU(fullApdu,
sizeof(fullApdu), response, responseLength)) {
295 _logger.println(
F(
"OpenSecureChannel: unexpected response size."));
300 _logger.println(
F(
"OpenSecureChannel: bad SW."));
305 _logger.println(
F(
"OpenSecureChannel APDU failed."));
336 uint8_t* clientPublicKey,
337 const uint8_t* clientPrivateKey,
339 const uint8_t* cardEphemeralPubKey) {
341 uint8_t sharedSecret[32U] = { 0U };
342 (void)clientPublicKey;
344 if (!
_crypto.ecdh(cardEphemeralPubKey, clientPrivateKey, sharedSecret, sessionCurve)) {
351 uint8_t sha512Output[64U] = { 0U };
353 const size_t concatLen = 32U + pairingKeyLen + 32U;
359 bool sha512Ok =
_crypto.sha512(concat, concatLen, sha512Output);
375 uint8_t RNG_data[32U] = { 0U };
376 if (!
_crypto.random(RNG_data,
sizeof(RNG_data))) {
388 uint8_t ciphertextOPC[48U] = { 0U };
389 uint16_t cipherLength =
_crypto.aesCbcEncrypt(RNG_data,
sizeof(RNG_data),
396 0x80U, 0x11U, 0x00U, 0x00U,
400 (void)
CW_Utils::safe_memcpy(MAC_apduHeader,
sizeof(MAC_apduHeader), opcApduHeader,
sizeof(opcApduHeader));
402 size_t MAC_data_length =
sizeof(MAC_apduHeader) + cipherLength;
403 uint8_t MAC_data[64U] = { 0U };
404 uint8_t ciphertextMACLong[64U] = { 0U };
406 if (MAC_data_length >
sizeof(MAC_data)) {
416 (void)
CW_Utils::safe_memcpy(MAC_data +
sizeof(MAC_apduHeader),
sizeof(MAC_data) -
sizeof(MAC_apduHeader), ciphertextOPC, cipherLength);
418 uint16_t encryptedLengthMAC =
_crypto.aesCbcEncrypt(MAC_data, (uint16_t)MAC_data_length,
424 uint8_t macOffset = (uint8_t)(encryptedLengthMAC -
AES_BLOCK_SIZE);
429 uint16_t offset = 0U;
430 (void)
CW_Utils::safe_memcpy(sendApduOpc + offset,
sizeof(sendApduOpc) -
static_cast<size_t>(offset), opcApduHeader,
sizeof(opcApduHeader));
431 offset +=
sizeof(opcApduHeader);
432 (void)
CW_Utils::safe_memcpy(sendApduOpc + offset,
sizeof(sendApduOpc) -
static_cast<size_t>(offset), MAC_value,
sizeof(MAC_value));
433 offset +=
sizeof(MAC_value);
434 (void)
CW_Utils::safe_memcpy(sendApduOpc + offset,
sizeof(sendApduOpc) -
static_cast<size_t>(offset), ciphertextOPC, cipherLength);
436 uint8_t response[255U] = { 0U };
437 uint8_t responseLength =
static_cast<uint8_t
>(
sizeof(response));
439 if (
_driver.sendAPDU(sendApduOpc,
sizeof(sendApduOpc), response, responseLength)) {
446 _logger.println(
F(
"MutualAuth: unexpected response size."));
451 _logger.println(
F(
"MutualAuth: bad SW."));
456 _logger.println(
F(
"MutualAuth APDU failed."));
502 const uint8_t apdu[], uint16_t apduLength,
503 const uint8_t data[], uint16_t dataLength,
504 uint8_t* decryptedOutput, uint16_t* decryptedOutputLength) {
510 _logger.println(
F(
"Error: data too large for encryption buffer."));
516 uint16_t encryptedLength =
_crypto.aesCbcEncrypt(data, dataLength,
s_dataBuf,
523 if (lcValue > 0xFFU) {
525 _logger.println(
F(
"Error: lcValue overflow — payload too large."));
536 macApdu[0U] = (uint8_t)lcValue;
538 uint16_t macDataLength = apduLength +
sizeof(macApdu) + encryptedLength;
541 _logger.println(
F(
"Error: MAC data length exceeds buffer."));
548 uint16_t offset = 0U;
550 offset += apduLength;
552 offset +=
sizeof(macApdu);
565 const uint8_t lc = (uint8_t)lcValue;
566 uint8_t sendApduLength = (uint8_t)(apduLength +
APDU_LC_LEN +
sizeof(macValue) + encryptedLength);
569 _logger.println(
F(
"Error: Send APDU length exceeds buffer."));
578 offset += apduLength;
582 offset +=
sizeof(macValue);
586 uint8_t response[255U] = { 0U };
587 uint8_t responseLength =
static_cast<uint8_t
>(
sizeof(response));
589 if (
_driver.sendAPDU(
s_apduBuf, sendApduLength, response, responseLength)) {
594 ret =
aesCbcDecrypt(session, response,
static_cast<size_t>(responseLength), macValue,
595 decryptedOutput, decryptedOutputLength);
601 }
else if (responseLength >= 2U) {
605 _logger.print(
F(
"Secured APDU: bad SW 0x"));
606 if (response[responseLength - 2U] < 0x10U) {
_logger.print(
F(
"0")); }
607 _logger.print(response[responseLength - 2U],
HEX);
608 if (response[responseLength - 1U] < 0x10U) {
_logger.print(
F(
"0")); }
609 _logger.println(response[responseLength - 1U],
HEX);
614 _logger.println(
F(
"Secured APDU failed."));
626 uint8_t* response,
size_t response_len,
628 uint8_t* decryptedOutput, uint16_t* decryptedOutputLength) {
631 if ((response == NULL) || (response_len < (
size_t)(
AES_BLOCK_SIZE + 2U + 1U))) {
639 size_t totalDataLen = response_len - 2U;
642 if (mac_value == NULL) {
648 if (macInputLen >
sizeof(
s_macBuf)) {
650 _logger.println(
F(
"Error: Response too large for MAC verification."));
656 s_macBuf[0] = (uint8_t)totalDataLen;
670 _logger.println(
F(
"MAC mismatch."));
677 uint16_t decryptedDataLength =
_crypto.aesCbcDecrypt(rep_data, (uint16_t)cipherLen,
s_dataBuf,
683 if (decryptedDataLength < 2U) {
685 _logger.println(
F(
"Error: Decoded data too short."));
688 else if (decryptedDataLength >
sizeof(
s_dataBuf)) {
690 _logger.println(
F(
"Error: Decoded data length exceeds buffer."));
694 uint8_t innerSW1 =
s_dataBuf[decryptedDataLength - 2U];
695 uint8_t innerSW2 =
s_dataBuf[decryptedDataLength - 1U];
696 uint16_t payloadLength = decryptedDataLength - 2U;
698 if ((innerSW1 != 0x90U) || (innerSW2 != 0x00U)) {
700 _logger.print(
F(
"Card error SW: 0x"));
701 if (innerSW1 < 0x10U) {
_logger.print(
F(
"0")); }
704 if (innerSW2 < 0x10U) {
_logger.print(
F(
"0")); }
712 if ((decryptedOutput != NULL) && (decryptedOutputLength != NULL)) {
714 *decryptedOutputLength = payloadLength;
733 uint16_t& pos, uint16_t& fieldLen) {
737 if ((buf != NULL) && (pos < bufLen)) {
738 uint8_t b = buf[pos];
742 fieldLen =
static_cast<uint16_t
>(b);
746 fieldLen =
static_cast<uint16_t
>(buf[pos]);
751 if ((pos + 1U) < bufLen) {
752 fieldLen =
static_cast<uint16_t
>(
753 static_cast<uint16_t
>(buf[pos]) << 8U);
754 fieldLen |=
static_cast<uint16_t
>(buf[pos + 1U]);
767static bool derSkipField(
const uint8_t* buf, uint16_t bufLen, uint16_t& pos) {
770 if ((buf != NULL) && (pos < bufLen)) {
771 uint16_t contentLen = 0U;
774 if ((pos + contentLen) <= bufLen) {
792 uint16_t& tbsMsgStart, uint16_t& tbsMsgLen,
793 const uint8_t*& pubKey65Ptr,
794 const uint8_t*& sigPtr, uint8_t& sigLen) {
797 uint16_t certContentLen = 0U;
798 uint16_t tbsContentLen = 0U;
799 uint16_t tbsEnd = 0U;
800 uint16_t spkiContentLen = 0U;
809 if ((buf == NULL) || (bufLen == 0U)) {
826 if ((pos + certContentLen) > bufLen) {
845 tbsMsgLen = (pos - tbsMsgStart) + tbsContentLen;
846 tbsEnd = pos + tbsContentLen;
847 if (tbsEnd > bufLen) {
855 if (ok && (pos < tbsEnd)) {
916 if ((pos + spkiContentLen) > bufLen) {
946 if ((pos + bsLen) > bufLen) {
961 pubKey65Ptr = buf + pos + 1U;
991 if ((pos + bsLen) > bufLen) {
1006 uint16_t rawSigLen = bsLen - 1U;
1007 if (rawSigLen > 255U) {
1010 sigPtr = buf + pos + 1U;
1011 sigLen =
static_cast<uint8_t
>(rawSigLen);
1022 if ((der != NULL) && (raw64 != NULL) && (derLen >= 6U) && (der[0] == 0x30U)) {
1024 if ((uint8_t)(der[1] + 2U) > derLen) {
1030 if (der[pos] == 0x02U) {
1032 uint8_t rLen = der[pos];
1038 if ((pos + rLen) <= derLen) {
1039 const uint8_t* rPtr = der + pos;
1042 if ((pos < derLen) && (der[pos] == 0x02U)) {
1044 uint8_t sLen = der[pos];
1050 if ((pos + sLen) <= derLen) {
1053 if ((pos + sLen) != (uint8_t)(2U + der[1])) {
1056 const uint8_t* sPtr = der + pos;
1058 memset(raw64, 0U, 64U);
1061 if ((rLen == 33U) && (rPtr[0] == 0x00U)) { rPtr++; rLen = 32U; }
1067 if ((sLen == 33U) && (sPtr[0] == 0x00U)) { sPtr++; sLen = 32U; }
1083 const uint8_t* message, uint16_t msgLen,
1084 const uint8_t* derSig, uint8_t derSigLen) {
1085 bool result =
false;
1086 uint8_t hash[32U] = { 0U };
1087 uint8_t rawSig[64U] = { 0U };
1089 bool hashOk =
_crypto.sha256(message, msgLen, hash);
1103 const uint8_t APDU_P2_IDX = 3U;
1104 uint8_t apdu[5U] = { 0x80U, 0xF7U, 0x00U, 0x00U, 0x00U };
1106 uint16_t responseLen =
static_cast<uint16_t
>(
sizeof(response));
1108 if (!
_driver.sendAPDULarge(apdu,
static_cast<uint8_t
>(
sizeof(apdu)), response,
1111 _logger.println(
F(
"getManufacturerCertificate APDU failed."));
1115 if (responseLen >
static_cast<uint16_t
>(
sizeof(response))) {
1117 _logger.println(
F(
"getManufacturerCertificate: driver reported overflow."));
1124 uint16_t dataBytes =
static_cast<uint16_t
>(
1127 if (dataBytes >= 2U) {
1128 uint16_t totalCertLen = (
static_cast<uint16_t
>(response[0]) << 8U)
1129 |
static_cast<uint16_t
>(response[1]);
1132 uint16_t certInPage =
static_cast<uint16_t
>(dataBytes - 2U);
1133 if (certInPage > totalCertLen) {
1134 certInPage = totalCertLen;
1137 static_cast<size_t>(certInPage));
1138 certLen = certInPage;
1140 uint8_t pageIdx = 1U;
1141 while ((certLen < totalCertLen) && (pageIdx < 8U)) {
1142 apdu[APDU_P2_IDX] = pageIdx;
1143 responseLen =
static_cast<uint16_t
>(
sizeof(response));
1145 if (!
_driver.sendAPDULarge(apdu,
static_cast<uint8_t
>(
sizeof(apdu)),
1146 response, responseLen)) {
1149 if (responseLen >
static_cast<uint16_t
>(
sizeof(response))) {
1151 _logger.println(
F(
"getManufacturerCertificate: driver reported overflow."));
1159 uint16_t pageData =
static_cast<uint16_t
>(
1161 uint16_t remaining =
static_cast<uint16_t
>(totalCertLen - certLen);
1162 if (pageData > remaining) {
1163 pageData = remaining;
1171 response,
static_cast<size_t>(pageData));
1172 certLen =
static_cast<uint16_t
>(certLen + pageData);
1176 ret = (certLen == totalCertLen);
1179 _logger.println(
F(
"getManufacturerCertificate: incomplete."));
1184 _logger.println(
F(
"getManufacturerCertificate: cert too large."));
1228 uint8_t cardCertLen) {
1231 if ((cardCert == NULL) || (cardCertLen < 80U) || (cardCert[0] != 0x43U)) {
1233 _logger.println(
F(
"verifyCert: invalid card cert."));
1245 if (mfCertLen == 0U) {
1248 _logger.println(
F(
"verifyCert: failed to get mfr cert."));
1252 }
else if (mfCertLen < 20U) {
1254 _logger.println(
F(
"verifyCert: pre-fetched mfr cert too short."));
1265 uint16_t tbsMsgStart = 0U;
1266 uint16_t tbsMsgLen = 0U;
1267 const uint8_t* pubKey65Ptr = NULL;
1268 const uint8_t* mfSigPtr = NULL;
1269 uint8_t mfSigLen = 0U;
1273 tbsMsgStart, tbsMsgLen,
1275 mfSigPtr, mfSigLen)) {
1277 _logger.println(
F(
"verifyCert: DER walk of mfr cert failed."));
1283 const uint8_t* devicePubKey64 = NULL;
1285 devicePubKey64 = pubKey65Ptr + 1U;
1288 uint16_t mfMsgLen = tbsMsgLen;
1290 bool mfVerified =
false;
1294 mfSigPtr, mfSigLen)) {
1301 _logger.println(
F(
"verifyCert: mfr cert sig INVALID — card NOT genuine."));
1307 _logger.println(
F(
"Manufacturer cert signature OK."));
1312 const uint8_t CARD_CERT_MSG_LEN = 74U;
1314 if (cardCertLen <= CARD_CERT_MSG_LEN) {
1316 _logger.println(
F(
"verifyCert: card cert too short for sig."));
1321 const uint8_t* cardSig = cardCert + CARD_CERT_MSG_LEN;
1322 uint8_t cardSigLen = cardCertLen - CARD_CERT_MSG_LEN;
1325 cardCert, CARD_CERT_MSG_LEN,
1326 cardSig, cardSigLen)) {
1328 _logger.println(
F(
"verifyCert: card cert sig INVALID."));
1334 _logger.println(
F(
"Card cert signature OK."));
1344 _logger.println(
F(
"verifyCert: nonce mismatch — possible replay."));
1352 _logger.println(
F(
"Certificate chain OK. Card is genuine."));
#define CW_CERT_MANUF_SIG_INVALID
#define CW_CERT_FORMAT_ERROR
#define CW_CERT_KEY_NOT_FOUND
#define CW_CERT_NONCE_SIZE
#define CW_MANUF_CERT_MAX_BYTES
#define CW_CERT_CARD_SIG_INVALID
#define CW_CERT_NONCE_MISMATCH
#define RESPONSE_STATUS_WORDS_IN_BYTES
static bool derSkipField(const uint8_t *buf, uint16_t bufLen, uint16_t &pos)
static bool derWalkMfCert(const uint8_t *buf, uint16_t bufLen, uint16_t &tbsMsgStart, uint16_t &tbsMsgLen, const uint8_t *&pubKey65Ptr, const uint8_t *&sigPtr, uint8_t &sigLen)
#define DER_EC_POINT_BYTES
#define RESPONSE_GETCARDCERTIFICATE_IN_BYTES
#define RESPONSE_SELECT_IN_BYTES
#define OPENSECURECHANNEL_SALT_IN_BYTES
#define REQUEST_MUTUALLYAUTHENTICATE_IN_BYTES
#define COMMON_PAIRING_DATA
#define RESPONSE_OPENSECURECHANNEL_IN_BYTES
#define DER_BIT_UNUSED_ZERO
#define INPUT_BUFFER_LIMIT
#define RESPONSE_MUTUALLYAUTHENTICATE_IN_BYTES
#define RESPONSE_GETMANUFACTURERCERT_PAGE_IN_BYTES
static uint8_t s_mfCertBuf[CW_MANUF_CERT_MAX_BYTES]
static uint8_t s_dataBuf[ENC_BUF_MAX_LEN]
static uint8_t s_macBuf[MAX_MAC_DATA_LEN]
#define DER_EC_UNCOMPRESSED
static uint8_t s_apduBuf[SEND_APDU_MAX_LEN]
#define DER_TAG_BIT_STRING
#define SEND_APDU_MAX_LEN
static bool derReadLength(const uint8_t *buf, uint16_t bufLen, uint16_t &pos, uint16_t &fieldLen)
#define CLIENT_PUBLIC_KEY_SIZE
#define GETCARDCERTIFICATE_IN_BYTES
#define DER_LEN_LONG_FLAG
Cryptnox secure channel protocol over NFC.
Cryptnox CA public keys used for offline certificate verification.
static const uint8_t *const CW_TRUSTED_CA_KEYS[CW_TRUSTED_CA_COUNT]
#define CW_TRUSTED_CA_COUNT
Platform-independent security and memory utilities.
Abstract interface for cryptographic operations used by CW_SecureChannel.
Abstract interface for serial/debug output.
Abstract interface for NFC transport operations.
CW_SecureChannel(CW_NfcTransport &driver, CW_Logger &logger, CW_CryptoProvider &crypto, CW_Platform &platform)
Construct a CW_SecureChannel.
static bool parseDerSigToRaw(const uint8_t *der, uint8_t derLen, uint8_t *raw64)
CW_Logger & _logger
Logging interface.
bool openSecureChannel(uint8_t *salt, uint8_t *clientPublicKey, uint8_t *clientPrivateKey, CW_Curve sessionCurve)
Send OPEN SECURE CHANNEL and retrieve the session salt.
CW_NfcTransport & _driver
NFC transport for APDU exchange.
bool mutuallyAuthenticate(CW_SecureSession &session, const uint8_t *salt, uint8_t *clientPublicKey, const uint8_t *clientPrivateKey, CW_Curve sessionCurve, const uint8_t *cardEphemeralPubKey)
Perform ECDH derivation and MUTUALLY AUTHENTICATE with the card.
bool aesCbcEncrypt(CW_SecureSession &session, const uint8_t apdu[], uint16_t apduLength, const uint8_t data[], uint16_t dataLength, uint8_t *decryptedOutput=NULL, uint16_t *decryptedOutputLength=NULL)
AES-CBC encrypt + MAC, send APDU, and decrypt response.
bool inListPassiveTarget()
Detect a passive NFC target (ISO-DEP card).
bool aesCbcDecrypt(const CW_SecureSession &session, uint8_t *response, size_t responseLen, uint8_t *macValue, uint8_t *decryptedOutput=NULL, uint16_t *decryptedOutputLength=NULL)
Verify MAC and decrypt an encrypted APDU response.
bool begin()
Initialize the NFC transport module.
bool verifyEcdsaSha256(const uint8_t *pubKey64, const uint8_t *message, uint16_t msgLen, const uint8_t *derSig, uint8_t derSigLen)
bool checkStatusWord(const uint8_t *response, uint16_t responseLength, uint8_t sw1Expected, uint8_t sw2Expected)
Verify the SW1/SW2 status word at the end of an APDU response.
bool preFetchManufacturerCert()
Fetch and cache the manufacturer certificate before getCardCertificate().
bool getCardCertificate(uint8_t *cardCertificate, uint8_t &cardCertificateLength)
Retrieve the card's ephemeral public key via GET CARD CERTIFICATE.
uint16_t _cachedMfCertLen
Non-zero when s_mfCertBuf holds a valid pre-fetched manufacturer certificate.
bool selectApdu()
Send the SELECT APDU to activate the Cryptnox application.
CW_Platform & _platform
Platform abstraction (sleep_ms).
uint8_t verifyCertificateChain(const uint8_t *cardCert, uint8_t cardCertLen)
Verify the full card certificate chain against the trusted CA.
void resetReader()
Reset the NFC reader hardware.
uint8_t _lastNonce[CW_CERT_NONCE_SIZE]
Nonce sent in the last getCardCertificate() call; checked in verifyCertificateChain().
bool extractCardEphemeralKey(const uint8_t *cardCertificate, uint8_t *cardEphemeralPubKey, uint8_t *fullEphemeralPubKey65=NULL)
Extract the card's ephemeral EC P-256 public key from a certificate.
CW_CryptoProvider & _crypto
Crypto operations (AES, SHA, ECDH, RNG).
bool getManufacturerCertificate(uint8_t *cert, uint16_t &certLen)
Retrieve the manufacturer certificate stored in card flash.
bool printFirmwareVersion()
Print the NFC reader firmware version to the logger.
static bool safe_memcpy(uint8_t *dst, size_t dstSize, const uint8_t *src, size_t count)
Safe memcpy — validates pointers, sizes, and checks for overlap.
static bool secure_compare(const uint8_t *a, const uint8_t *b, size_t len)
Constant-time buffer comparison, resistant to timing side-channel attacks.
static void secure_wipe(uint8_t *buf, size_t len)
Securely zero a buffer, guaranteed not to be optimised away.
CW_Curve
Portable curve identifier used throughout the SDK.
Holds cryptographic session state for reentrant secure channel operations.
uint8_t macKey[CW_MACKEY_SIZE]
void clear()
Securely clear all session keys and IV.
uint8_t aesKey[CW_AESKEY_SIZE]