diff --git a/CHANGES.md b/CHANGES.md index f578f5e..ccc36cb 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,179 @@ MatrixSSL Release Notes ======================= +Changes in 3.8.7 +---------------- + +> **Version 3.8.7** +> November 2016 +> (C) Copyright 2016 INSIDE Secure - All Rights Reserved + + + +1. BUG FIXES SINCE 3.8.6 + - Fixed Wrong Computation Results Bug In pstm.c Division + - Fixed Memory Corruption In psDhImportPubKey + - Fixed RSA Public Key Read Overflow + - X.509/CRL/OCSP Timestamp Validation + - Unix Year 2038 Problem Fix + - Stricter OID Comparison + - Multibyte String Handling + - Configuration Robustness Improvements + - X.509 Certificate Parsing Read Overflow + - PKCS #8 Buffer Read Overflow + - OCSP Bug Fixes + - Generic Bug Fixes For Test Programs + - Changes to Recommended Configurations + - psMutex Locking and Unlocking APIs Compiler Warnings Removed + - MD5 and SHA-1 Combined Digest Function + - Coverity Issues Fixed + - Yarrow Build Issues Fixed + +2. NEW FEATURES SINCE 3.8.6 + - SHA-512 for X.509 Certificates Improvements + - OCSP Improvements + - X.509 Certificate Domain Components + - New Configuration: Minimal PSK + + +#1. BUG FIXES SINCE 3.8.6 + +## Fixed Wrong Computation Results Bug In pstm.c Division + +The bug could cause some big number mathematics to return wrong values when divisor and dividend are very far from each other. +This issue is related to public key computation problems +reported by Security Researcher [Hanno Böck](https://hboeck.de/). + +## Fixed Memory Corruption In psDhImportPubKey + +Importing Diffie-Hellman public key cleared some memory beyond end of the key. +On some systems this bug may have caused memory corruption. + +## Fixed RSA Public Key Read Overflow + +When importing RSA key from certificate, maliciously crafted RSA public key could cause read buffer overflow and crash. + +## X.509/CRL/OCSP Timestamp Validation + +MatrixSSL accepted some X.509 certificates with illegal timestamps, +such as leap day in an ordinary year. In additional, some two +digit years were parsed incorrectly. Timestamp parsing has been +altered everywhere to use new psBrokenDownDate API, which correctly +handles these corner cases. Some of X.509 time parsing issues were +reported by Sze Yiu Chau. + +## Unix Year 2038 Problem Fix + +On 32-bit Unix devices, time_t type, which is signed will overflow in 2038. +A workaround was added that will allow timestamps and dates to be processed +correctly by MatrixSSL on and after Tuesday 19 January 2038. + +## Stricter OID Comparison + +The OID comparison in MatrixSSL uses a simple non-cryptographic digest +function, based on sum of bytes, which is not collision free. Comparison of OID +binary representation was added to ensure unknown OIDs are not accidentally +interpreted the same than some of existing OIDs. +This issue was reported by Sze Yiu Chau. + +## Multibyte String Handling + +The MatrixSSL now includes function to recode strings containing multibyte +(BMPString) characters as UTF-8 strings. This handling is applied to +X.509 certificate fields, such as Subject Name. This allows code using +MatrixSSL to work with BMPString input without actually knowing the encoding +used. + +## Configuration Robustness Improvements + +MatrixSSL has been made more robust with configurations: changing +configuration options is less likely to cause problems building the software. + +These improvements allow smaller configurations for embedded systems. +(E.g. build without DTLS, or build only server-side or client-side support.) + +## X.509 Certificate Parsing Read Overflow + +Fixed read overflow from X.509 certificate date handling and +removed possible buffer read overflow in parseGeneralNames(). +Without these fixes maliciously crafted X.509 certificate could +cause software crash. + + +## PKCS #8 Buffer Read Overflow + +Fixed reading overly large invalid PKCS #8 encoded private key. +Without this fix, maliciously crafted PKCS #8 file could cause +software crash. + + +## OCSP Bug Fixes + +In lieu of OCSP improvements, small bugs in OCSP implementation have +been fixed. The most notable bug was a memory leak. + + +## Generic Bug Fixes For Test Programs + +Removed some warnings and memory leaks from test programs. +Made test programs confirm to Unix/POSIX return value scheme on relevant +platforms. + + +## Changes to Recommended Configurations + +The recommended configurations have been edited slightly. +Most notably, the tracing is disabled by default on non-debug configurations. + + +## psMutex Locking and Unlocking APIs Compiler Warnings Removed + +Removed return value from psLockMutex() and psUnlockMutex() APIs. +This removes several warnings regarding return values not being used. + + +## MD5 and SHA-1 Combined Digest Function + +The MatrixSSL will now invoke combined MD5 and SHA-1 hash function `psMd5Sha1`, +whenever possible instead of separate MD5 and SHA-1 hash functions. + +## Coverity Issues Fixed + +Implementation of `getTicketKeys` and `parseSSLHandshake` +functions was changed to remove issues detected by Coverity. + +## Yarrow Build Issues Fixed + +MatrixSSL comes with a version of Yarrow PRNG. Its use has been deprecated, +but the PRNG continued to be shipped with MatrixSSL. Unfortunately, the +latest versions of MatrixSSL had compilation errors in yarrow.c. +Those errors have been fixed, and the source code file has been marked +deprecated. + +#2. NEW FEATURES SINCE 3.8.6 + +## SHA-512 for X.509 Certificates Improvements + +MatrixSSL can use SHA-512 to sign self-signed certificate or certificate request. SHA-512 was already previously supported for verification of X.509 certificates. +(This feature can be used only on MatrixSSL Commercial Edition.) + +## OCSP Improvements + +OCSP example application apps/crypto/ocsp.c +(Commercial Edition Only) and MatrixSSL Developer Guide have +been improved to give more documentation regarding OCSP request. +OCSP request can now use requestorId feature and request status of list of certificates. + +## X.509 Certificate Domain Components + +Added Functions for obtaining contents of X.509 certificate Domain +Component field(s). + +## New Configuration: Minimal PSK + +New configuration psk added. This configuration provides small footprint MatrixSSL build with only Pre-Shared Key and TLS 1.2 functionality using Matrix Crypto. + + Changes in 3.8.6 ---------------- @@ -40,7 +213,7 @@ In some cases RSA key generation of 4096 bit keys would fail and return with an Warnings across multiple platforms and compilers were fixed. Various compile time configuration combination build issues were fixed. ##MatrixSSH compatibility issue -Newer versions of MatrixSSH server were incompatible with the PuTTY client. A fix has been included and enabled by default `USE_PUTTY_WORKAROUND`. +Newer versions of MatrixSSH server were incompatible with the PuTTY client. A fix has been included and enabled by default `USE_PUTTY_WORKAROUND`. *Note this does not affect the standard MatrixSSL codebase*. #2 FEATURES AND IMPROVEMENTS @@ -283,7 +456,7 @@ HMAC-SHA1 or HMAC-SHA256 are now used to generate the DTLS cookie, and additiona ##Fixed key type verification for chosen cipher suite An internal verification function that determined whether the server key type was correct for the chosen cipher suite has now been fixed. Previous versions would sometimes incorrectly determine the server was using the wrong key type if the server was using a certificate chain where parent certificates did not use the same key type. This bug resulted in a failed handshake and is now fixed. -##Validation of RSA Signature Creation +##Validation of RSA Signature Creation An internal RSA validation of created signatures has been added to the library in the `psRsaEncryptPriv()` function. Security researcher Florian Weimer has shown it is possible for RSA private key information to leak under some special failure circumstances. Information on the exploit can be found here: https://people.redhat.com/~fweimer/rsa-crt-leaks.pdf @@ -360,7 +533,7 @@ Test keys and certificates moved from ./sampleCerts to ./testkeys. XCode and Visual Studio projects moved to ./xcode and ./visualstudio. Several file changes and renames are present as well: - + TLS Decoding moved ./matrixssl/sslDecode.c from ./matrixssl/sslDecode.c, ./matrixssl/hsDecode.c and ./matrixssl/extDecode.c. Private key import/export from ./crypto/pubkey/pkcs.c. to diff --git a/Makefile b/Makefile index 14317eb..d42eca7 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,11 @@ # using the MatrixSSL stock crypto. # make all-rsaonly Build MatrixSSL using options that disable ECC and DH, # using the MatrixSSL stock crypto. +# make all-psk Build MatrixSSL with support for only a single PSK +# ciphersuite using MatrixSSL stock crypto. +# This is the smallest possible configuration, +# except that both server- and client-side TLS are enabled +# for easier testing. # # Additional targets for MatrixSSL FIPS Edition # @@ -111,6 +116,11 @@ all-rsaonly: make $(CONFIG_NONFIPS_PREFIX)rsaonly-config make all +# Only support RSA (MatrixSSL stock crypto) +all-psk: + make $(CONFIG_NONFIPS_PREFIX)psk-config + make all + # A commonly recommended set of options for MatrixSSL using stock crypto, # for the most common TLS use cases. This configuration disables # DH and 3DES options in rare use (which is typically considered good for @@ -205,7 +215,7 @@ apps_crypto: #endif /* MATRIXSSL_COMMERCIAL */ apps: $(APPS_ADDITIONAL) - $(MAKE) --directory=apps/ssl + if make --directory=matrixssl parse-config | grep -q '#define USE_ZLIB_COMPRESSION'; then EXTRA_LDFLAGS=-lz $(MAKE) --directory=apps/ssl; else $(MAKE) --directory=apps/ssl; fi; $(MAKE) --directory=apps/dtls clean: diff --git a/apps/dtls/dtlsClient.c b/apps/dtls/dtlsClient.c index c71349a..209a636 100644 --- a/apps/dtls/dtlsClient.c +++ b/apps/dtls/dtlsClient.c @@ -68,6 +68,18 @@ typedef struct { //#define ID_ECDH_ECDSA /* EC Certificate and Key */ //#define ID_ECDH_RSA /* EC Key with RSA signed certificate */ +#if !defined(ID_RSA) && !defined(ID_ECDH_ECDSA) && !defined(ID_ECDH_RSA) +/* Choose a default identity based on which algorithms are supported. */ +#ifdef USE_RSA_CIPHER_SUITE +#define ID_RSA +#else +#ifdef USE_ECC_CIPHER_SUITE +#define ID_ECDH_ECDSA +#else +#error "Please enable either RSA or ECC for client" +#endif /* USE_ECC_CIPHER_SUITE */ +#endif /* USE_RSA_CIPHER_SUITE */ +#endif /* !ID_RSA && !ID_ECDH_ECDSA && !ID_ECDH_RSA */ /* If the algorithm type is supported, load a CA for it */ #ifdef USE_HEADER_KEYS diff --git a/apps/dtls/dtlsServer.c b/apps/dtls/dtlsServer.c index 8155855..d291b0a 100644 --- a/apps/dtls/dtlsServer.c +++ b/apps/dtls/dtlsServer.c @@ -46,7 +46,6 @@ /* #define USE_CERT_VALIDATOR */ -#define DTLS_PORT 4433 static int packet_loss_prob = 0; /* Reciprocal of packet loss probability (i.e. P(packet loss) = 1/x). Default value is 0 (no packet loss). */ @@ -324,6 +323,7 @@ static int exitFlag; static uint32_t g_rsaKeySize; static uint32_t g_eccKeySize; static uint32_t g_ecdhKeySize; +static int g_port; #ifdef USE_CERT_VALIDATOR /******************************************************************************/ @@ -370,6 +370,7 @@ static void usage(void) "-l - Reciprocal of packet loss probability\n" " (for packet loss simulation tests)\n" #endif /* DTLS_PACKET_LOSS_TEST */ + "-p - Port number to use\n" ); } @@ -384,7 +385,7 @@ static int32 process_cmd_options(int32 argc, char **argv) g_eccKeySize = g_ecdhKeySize = 256; opterr = 0; - while ((optionChar = getopt(argc, argv, "hr:e:d:l:")) != -1) + while ((optionChar = getopt(argc, argv, "hr:e:d:l:p:")) != -1) { switch (optionChar) { case '?': @@ -433,6 +434,12 @@ static int32 process_cmd_options(int32 argc, char **argv) } break; #endif /* DTLS_PACKET_LOSS_TEST */ + case 'p': + g_port = atoi(optarg); + if (g_port < 0) { + printf("invalid -p option\n"); + return -1; + } } } @@ -753,11 +760,11 @@ int main(int argc, char ** argv) goto CLIENT_EXIT; } - if ((sock = newUdpSocket(NULL, DTLS_PORT, &err)) == INVALID_SOCKET) { + if ((sock = newUdpSocket(NULL, g_port, &err)) == INVALID_SOCKET) { _psTrace("Error creating UDP socket\n"); goto DTLS_EXIT; } - _psTraceInt("DTLS server running on port %d\n", DTLS_PORT); + _psTraceInt("DTLS server running on port %d\n", g_port); /* Server loop */ for (exitFlag = 0; exitFlag == 0;) { diff --git a/apps/ssl/Makefile b/apps/ssl/Makefile index d4b8e9f..54fc2dd 100644 --- a/apps/ssl/Makefile +++ b/apps/ssl/Makefile @@ -34,10 +34,11 @@ STATIC:=\ $(MATRIXSSL_ROOT)/crypto/libcrypt_s.a \ $(MATRIXSSL_ROOT)/core/libcore_s.a -CIPHER_OPTION=ID_RSA # The default cipher option -CFLAGS+=-D$(CIPHER_OPTION) - -all: compile +# Allow selecting the client auth identity (ID_RSA, ID_ECDH_ECDSA, +# etc.) via an environment variable. +ifneq '$(CIPHER_OPTION)' '' + CFLAGS+=-D$(CIPHER_OPTION) +endif compile: $(OBJS) $(EXE) diff --git a/apps/ssl/client.c b/apps/ssl/client.c index bf8b6ca..0f35340 100644 --- a/apps/ssl/client.c +++ b/apps/ssl/client.c @@ -32,6 +32,7 @@ */ /******************************************************************************/ +#include #include #include #include @@ -60,6 +61,21 @@ //#define ID_ECDH_ECDSA /* EC Certificate and Key */ //#define ID_ECDH_RSA /* EC Key with RSA signed certificate */ +#if !defined(ID_RSA) && !defined(ID_ECDH_ECDSA) && !defined(ID_ECDH_RSA) +/* Choose a default identity based on which algorithms are supported. */ +#ifdef USE_RSA_CIPHER_SUITE +#define ID_RSA +#else +#ifdef USE_ECC_CIPHER_SUITE +#define ID_ECDH_ECDSA +#else +#ifndef USE_PSK_CIPHER_SUITE +#error "Please enable either RSA or ECC for client when not using PSK" +#endif /* !USE_PSK_CIPHER_SUITE */ +#endif /* USE_ECC_CIPHER_SUITE */ +#endif /* USE_RSA_CIPHER_SUITE */ +#endif /* !ID_RSA && !ID_ECDH_ECDSA && !ID_ECDH_RSA */ + #define USE_HEADER_KEYS #define ALLOW_ANON_CONNECTIONS 1 #define CRL_MAX_LENGTH 1048576 /* Maximum length for CRL: 1 megabyte. */ @@ -880,7 +896,7 @@ static int32 process_cmd_options(int32 argc, char **argv) */ int32 main(int32 argc, char **argv) { - int32 rc, CAstreamLen, i; + int32 rc, CAstreamLen, i, exit_code; sslKeys_t *keys; sslSessionId_t *sid = NULL; struct g_sslstats stats; @@ -890,14 +906,16 @@ int32 main(int32 argc, char **argv) WSAStartup(MAKEWORD(1, 1), &wsaData); #endif + exit_code = 0; + if ((rc = matrixSslOpen()) < 0) { _psTrace("MatrixSSL library init failure. Exiting\n"); - return rc; + return EXIT_FAILURE; } if (matrixSslNewKeys(&keys, NULL) < 0) { _psTrace("MatrixSSL library key init failure. Exiting\n"); - return -1; + return EXIT_FAILURE; } if (0 != process_cmd_options(argc, argv)) { @@ -963,7 +981,7 @@ int32 main(int32 argc, char **argv) #ifdef ID_RSA rc = loadRsaKeys(g_key_len, keys, CAstream, CAstreamLen); if (rc < 0) { - return rc; + return EXIT_FAILURE; } #endif @@ -975,7 +993,7 @@ int32 main(int32 argc, char **argv) if (CAstream) psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); - return rc; + return EXIT_FAILURE; } #endif @@ -987,7 +1005,7 @@ int32 main(int32 argc, char **argv) if (CAstream) psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); - return rc; + return EXIT_FAILURE; } #endif @@ -1039,7 +1057,7 @@ int32 main(int32 argc, char **argv) if (CAstream) psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); - return rc; + return EXIT_FAILURE; } #endif @@ -1050,7 +1068,7 @@ int32 main(int32 argc, char **argv) if (CAstream) psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); - return rc; + return EXIT_FAILURE; } #endif @@ -1061,7 +1079,7 @@ int32 main(int32 argc, char **argv) if (CAstream) psFree(CAstream, NULL); matrixSslDeleteKeys(keys); matrixSslClose(); - return rc; + return EXIT_FAILURE; } #endif @@ -1113,7 +1131,8 @@ int32 main(int32 argc, char **argv) rc = httpsClientConnection(keys, sid, &stats); if (rc < 0) { printf("F %d/%d\n", i, g_new); - return 0; + exit_code = EXIT_FAILURE; + goto out; } else { printf("N"); fflush(stdout); } @@ -1143,6 +1162,8 @@ int32 main(int32 argc, char **argv) rc = httpsClientConnection(keys, sid, &stats); if (rc < 0) { printf("f %d/%d\n", i, g_resumed); + exit_code = EXIT_FAILURE; + goto out; } else { printf("R"); fflush(stdout); } @@ -1170,16 +1191,20 @@ int32 main(int32 argc, char **argv) #endif } +out: matrixSslDeleteSessionId(sid); matrixSslDeleteKeys(keys); matrixSslClose(); + if (rc == MATRIXSSL_SUCCESS) + printf("TLS handshake complete.\n"); + #ifdef WIN32 _psTrace("Press any key to close"); getchar(); #endif - return 0; + return exit_code; } /******************************************************************************/ @@ -1631,37 +1656,59 @@ static int32_t fetchParseAndAuthCRLfromCert(psPool_t *pool, psX509Cert_t *cert, return PS_SUCCESS; } -/* Example function to retrieve a CRL using HTTP GET over POSIX sockets. - crlBuf is allocated by this routine and must be freed via psFree - - < 0 - Error loading CRL - 0 - Success +/** + Return the number of bytes difference between 'end' and 'start'. + @param[in] end A pointer to valid memory, greater or equal to 'start' + @param[in] start A pointer to valid memory, less than or equal to 'start' + @param sanity The maximum expected difference in bytes + @return Number of bytes that 'end' is greater than 'start'. Range is 0 <= return <= sanity. + If end < start, 0 is returned. If 'end' - 'start' > 'sanity', 'sanity' is returned. */ -static unsigned char crl_getHdr[] = "GET "; -#define GET_OH_LEN 4 -static unsigned char crl_httpHdr[] = " HTTP/1.0\r\n"; -#define HTTP_OH_LEN 11 -static unsigned char crl_hostHdr[] = "Host: "; -#define HOST_OH_LEN 6 -static unsigned char crl_acceptHdr[] = "\r\nAccept: */*\r\n\r\n"; -#define ACCEPT_OH_LEN 17 - -#define HOST_ADDR_LEN 64 /* max to hold 'www.something.com' */ -#define GET_REQ_LEN 128 /* max to hold http GET request */ - -#define HTTP_REPLY_CHUNK_SIZE 2048 +__inline static size_t ptrdiff_safe(const void *end, const void *start, size_t sanity) +{ + ptrdiff_t d; + if (end < start) { + return 0; + } + d = end - start; + if (d > sanity) { + return sanity; + } + return (size_t)d; +} +/** + Example function to retrieve a CRL using HTTP GET over POSIX sockets. + @security This API does not fully validate all input. It should only be used to fetch + a CRL froa trusted source with validly generated CRL data. The HTTP response of the + trusted server should also be tested, as the HTTP parsing in this API is not flexible. + @param [out] crlBuf is allocated by this routine and must be freed via psFree + @return < 0 Error loading CRL. 0 on Success +*/ int32 fetchCRL(psPool_t *pool, char *url, uint32_t urlLen, unsigned char **crlBuf, uint32_t *crlBufLen) { + static unsigned char crl_getHdr[] = "GET "; + #define GET_OH_LEN 4 + static unsigned char crl_httpHdr[] = " HTTP/1.0\r\n"; + #define HTTP_OH_LEN 11 + static unsigned char crl_hostHdr[] = "Host: "; + #define HOST_OH_LEN 6 + static unsigned char crl_acceptHdr[] = "\r\nAccept: */*\r\n\r\n"; + #define ACCEPT_OH_LEN 17 + #define HOST_ADDR_LEN 64 /* max to hold 'www.something.com' */ + #define GET_REQ_LEN 128 /* max to hold http GET request */ + #define HTTP_REPLY_CHUNK_SIZE 2048 + SOCKET fd; struct hostent *ip; struct in_addr intaddr; char *pageStart, *replyPtr, *ipAddr; char hostAddr[HOST_ADDR_LEN], getReq[GET_REQ_LEN]; int hostAddrLen, getReqLen, pageLen; - int32 transferred, sawOK, sawContentLength, grown; - int32 err, httpUriLen, port, offset; + ssize_t transferred; + int32_t grown = 0; + int32_t sawOK, sawContentLength, err, httpUriLen, port, offset; unsigned char crlChunk[HTTP_REPLY_CHUNK_SIZE + 1]; unsigned char *crlBin; /* allocated */ uint32_t crlBinLen; @@ -1844,7 +1891,7 @@ int32 fetchCRL(psPool_t *pool, char *url, uint32_t urlLen, } /* So how much do we actually have to copy our of first chunk? */ - transferred = transferred - (replyPtr - (char*)crlChunk); + transferred -= ptrdiff_safe(replyPtr, crlChunk, HTTP_REPLY_CHUNK_SIZE); if (sawContentLength) { /* Will march crlBin forward so just assign output crlBuf now */ @@ -1968,7 +2015,7 @@ int32 main(int32 argc, char **argv) { printf("USE_CLIENT_SIDE_SSL must be enabled in matrixsslConfig.h at build" \ " time to run this application\n"); - return -1; + return EXIT_FAILURE; } #endif /* USE_CLIENT_SIDE_SSL */ diff --git a/apps/ssl/server.c b/apps/ssl/server.c index 13c5e09..f1bb371 100644 --- a/apps/ssl/server.c +++ b/apps/ssl/server.c @@ -925,17 +925,21 @@ int32 main(int32 argc, char **argv) /* Still don't have a generic key loading function. Try RSA first and then ECC if that doesn't load */ +#ifdef USE_RSA if ((rc = matrixSslLoadRsaKeys(keys, certpath, keypath, g_password, capath)) < 0) { +#endif /* USE_RSA */ #ifdef USE_ECC_CIPHER_SUITE if ((rc = matrixSslLoadEcKeys(keys, certpath, keypath, g_password, capath)) < 0) { _psTrace("Unable to load key material. Exiting\n"); return rc; } #else - _psTrace("Unable to load key material. Possibly ECC key?\n"); - return rc; -#endif + _psTrace("Unable to load key material. Please enable RSA or ECC from config.\n"); + return rc; +#endif /* USE_ECC_CIPHER_SUITE */ +#ifdef USE_RSA } +#endif /* USE_RSA */ #ifdef REQUIRE_DH_PARAMS diff --git a/configs/default/cryptoConfig.h b/configs/default/cryptoConfig.h index 3a07dc4..ee9af57 100644 --- a/configs/default/cryptoConfig.h +++ b/configs/default/cryptoConfig.h @@ -44,7 +44,7 @@ //#define USE_CRYPTO_TRACE #ifdef DEBUG -//#define CRYPTO_ASSERT /**< Extra sanity asserts */ +#define CRYPTO_ASSERT/**< Extra sanity asserts */ #endif /******************************************************************************/ @@ -74,10 +74,10 @@ */ #define USE_RSA #define USE_ECC -#define USE_DH +//#define USE_DH /**< @note Enable verification of DSA signatures in certificate validation. - Works only when using the CL/SL library. */ -//#define USE_DSA_VERIFY + Works only when using the CL/SL library. @pre USE_CERT_PARSE. */ +#define USE_DSA_VERIFY /******************************************************************************/ /** @@ -92,11 +92,11 @@ @see http://csrc.nist.gov/groups/ST/toolkit/documents/dss/NISTReCur.pdf */ #ifdef USE_ECC - #define USE_SECP192R1/**< @security FIPS allowed for sig ver only. */ - #define USE_SECP224R1 +//#define USE_SECP192R1 /**< @security FIPS allowed for sig ver only. */ +//#define USE_SECP224R1 #define USE_SECP256R1/**< @security NIST_SHALL */ #define USE_SECP384R1/**< @security NIST_SHALL */ - #define USE_SECP521R1 +//#define USE_SECP521R1 #endif /** @@ -116,7 +116,7 @@ Symmetric and AEAD ciphers. @security Deprecated ciphers must be enabled in cryptolib.h */ -//#define USE_AES /* Enable/Disable AES */ +#define USE_AES/* Enable/Disable AES */ #define USE_AES_CBC #define USE_AES_GCM @@ -136,7 +136,8 @@ @security MD5 is deprecated, but still required in combination with SHA-1 for TLS handshakes before TLS 1.2, meaning that the strength is at least - that of SHA-1 in this usage. The only other usage of MD5 by TLS is for + that of SHA-1 in this usage. The define USE_MD5SHA1 can be used to enable + MD5 only for this purpose. The only other usage of MD5 by TLS is for certificate signatures and MD5 based cipher suites. Both of which are disabled at compile time by default. @@ -167,7 +168,7 @@ */ #define USE_MD5 #define USE_MD5SHA1/* Required for < TLS 1.2 Handshake */ -#define USE_HMAC_MD5/* TODO currently needed for prf */ +//#define USE_HMAC_MD5 /** @security MD2 is considered insecure, but is sometimes used for @@ -185,14 +186,14 @@ X.509 Certificates/PKI */ #define USE_BASE64_DECODE -#define USE_X509 -#define USE_CERT_PARSE/**< Usually required. @pre USE_X509 */ +#define USE_X509/**< Enable minimal X.509 support. */ +#define USE_CERT_PARSE/**< Enable TBSCertificate parsing. Usually required. @pre USE_X509 */ #define USE_FULL_CERT_PARSE/**< @pre USE_CERT_PARSE */ /**< Support extra distinguished name attributes that SHOULD be supported according to RFC 5280. */ //#define USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD /**< Support extra distinguished name attributes not mentioned in RFC 5280. */ //#define USE_EXTRA_DN_ATTRIBUTES -//#define ENABLE_CA_CERT_HASH /**< Used only for TLS trusted CA ind ext. */ +#define ENABLE_CA_CERT_HASH/**< Used only for TLS trusted CA ind ext. */ //#define ENABLE_MD5_SIGNED_CERTS /** @security Accept MD5 signed certs? */ #define ENABLE_SHA1_SIGNED_CERTS/** @security Accept SHA1 signed certs? */ /**< @security Allow parsing of locally trusted v1 root certs? */ @@ -206,10 +207,12 @@ */ #define USE_PRIVATE_KEY_PARSING //#define USE_PKCS5 /**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +/**< Enable PBKDF1 in priv key PEM encryption. @pre USE_PKCS5 and @pre USE_MD5. @security Not recommended. */ +#define USE_PBKDF1 #define USE_PKCS8/* Alternative private key storage format */ -#define USE_PKCS12/**< @pre USE_PKCS8 */ -#define USE_PKCS1_OAEP/* OAEP padding algorithm */ -#define USE_PKCS1_PSS/* PSS padding algorithm */ +//#define USE_PKCS12 /**< @pre USE_PKCS8 */ +//#define USE_PKCS1_OAEP /* OAEP padding algorithm */ +//#define USE_PKCS1_PSS /* PSS padding algorithm */ #endif /* _h_PS_CRYPTOCONFIG */ diff --git a/configs/default/matrixsslConfig.h b/configs/default/matrixsslConfig.h index fdfc689..8d113cd 100644 --- a/configs/default/matrixsslConfig.h +++ b/configs/default/matrixsslConfig.h @@ -124,16 +124,16 @@ extern "C" { //#define USE_TLS_DHE_PSK_WITH_AES_256_CBC_SHA /**< @security NIST_SHOULD_NOT */ /** Ephemeral ECC DH keys, RSA certificates */ -//#define USE_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA /**< @security NIST_SHOULD */ +#define USE_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA/**< @security NIST_SHOULD */ /** Pre-Shared Key Ciphers. NIST SP 800-52 Rev 1 recommends against using PSK unless neccessary See NIST SP 800-52 Rev 1 Appendix C */ -#define USE_TLS_PSK_WITH_AES_128_CBC_SHA/**< @security NIST_SHOULD_NOT */ -#define USE_TLS_PSK_WITH_AES_256_CBC_SHA/**< @security NIST_SHOULD_NOT */ +//#define USE_TLS_PSK_WITH_AES_128_CBC_SHA /**< @security NIST_SHOULD_NOT */ +//#define USE_TLS_PSK_WITH_AES_256_CBC_SHA /**< @security NIST_SHOULD_NOT */ /* TLS 1.2 ciphers */ -#define USE_TLS_PSK_WITH_AES_128_CBC_SHA256/**< @security NIST_SHOULD_NOT */ -#define USE_TLS_PSK_WITH_AES_256_CBC_SHA384/**< @security NIST_SHOULD_NOT */ +//#define USE_TLS_PSK_WITH_AES_128_CBC_SHA256 /**< @security NIST_SHOULD_NOT */ +//#define USE_TLS_PSK_WITH_AES_256_CBC_SHA384 /**< @security NIST_SHOULD_NOT */ /** Non-Ephemeral ECC DH keys, ECC DSA certificates */ #define USE_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA/**< @security NIST_MAY */ @@ -145,16 +145,16 @@ extern "C" { #define USE_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384/**< @security NIST_MAY */ /** Non-Ephemeral ECC DH keys, RSA certificates */ -#define USE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA -#define USE_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA +//#define USE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA +//#define USE_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA /* TLS 1.2 ciphers */ -#define USE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 -#define USE_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 -#define USE_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 -#define USE_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 +//#define USE_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 +//#define USE_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 +//#define USE_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 +//#define USE_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 /** Non-Ephemeral RSA keys/certificates */ -//#define USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA /**< @security NIST_SHALL */ +#define USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA/**< @security NIST_SHALL */ /** @note Some of (non-mandatory) cipher suites mentioned in NIST SP 800-52 Rev 1 are not supported by the MatrixSSL / MatrixDTLS. @@ -175,7 +175,7 @@ extern "C" { @security Do not cache Ephemeral ECC keys as it is against some standards, including NIST SP 800-56A, when in FIPS 140-2 mode of operation. */ -//#define NO_ECC_EPHEMERAL_CACHE /**< @security NIST_SHALL */ +#define NO_ECC_EPHEMERAL_CACHE/**< @security NIST_SHALL */ /******************************************************************************/ /** @@ -242,7 +242,7 @@ extern "C" { sha1 hash of each CA file to the server for help in server selection. This extra level of define is to help isolate the SHA1 requirement */ -//#define USE_TRUSTED_CA_INDICATION /**< @security NIST_SHOULD */ +#define USE_TRUSTED_CA_INDICATION/**< @security NIST_SHOULD */ /******************************************************************************/ /** @@ -285,7 +285,7 @@ extern "C" { however, this will also immediately expire SESSION_TICKETS below. */ #ifdef USE_SERVER_SIDE_SSL -#define SSL_SESSION_TABLE_SIZE 32 +#define SSL_SESSION_TABLE_SIZE 64 #define SSL_SESSION_ENTRY_LIFE (86400*1000)/* one day, in milliseconds */ #endif @@ -296,7 +296,7 @@ extern "C" { SSL_SESSION_TICKET_LIST_LEN is the max size of the server key list. */ #define USE_STATELESS_SESSION_TICKETS -#define SSL_SESSION_TICKET_LIST_LEN 32 +#define SSL_SESSION_TICKET_LIST_LEN 64 /******************************************************************************/ /** diff --git a/configs/noecc/cryptoConfig.h b/configs/noecc/cryptoConfig.h index 960f95b..dbb1072 100644 --- a/configs/noecc/cryptoConfig.h +++ b/configs/noecc/cryptoConfig.h @@ -76,7 +76,7 @@ //#define USE_ECC #define USE_DH /**< @note Enable verification of DSA signatures in certificate validation. - Works only when using the CL/SL library. */ + Works only when using the CL/SL library. @pre USE_CERT_PARSE. */ //#define USE_DSA_VERIFY /******************************************************************************/ @@ -136,7 +136,8 @@ @security MD5 is deprecated, but still required in combination with SHA-1 for TLS handshakes before TLS 1.2, meaning that the strength is at least - that of SHA-1 in this usage. The only other usage of MD5 by TLS is for + that of SHA-1 in this usage. The define USE_MD5SHA1 can be used to enable + MD5 only for this purpose. The only other usage of MD5 by TLS is for certificate signatures and MD5 based cipher suites. Both of which are disabled at compile time by default. @@ -167,7 +168,7 @@ */ #define USE_MD5 #define USE_MD5SHA1/* Required for < TLS 1.2 Handshake */ -#define USE_HMAC_MD5/* TODO currently needed for prf */ +#define USE_HMAC_MD5 /** @security MD2 is considered insecure, but is sometimes used for @@ -185,8 +186,8 @@ X.509 Certificates/PKI */ #define USE_BASE64_DECODE -#define USE_X509 -#define USE_CERT_PARSE/**< Usually required. @pre USE_X509 */ +#define USE_X509/**< Enable minimal X.509 support. */ +#define USE_CERT_PARSE/**< Enable TBSCertificate parsing. Usually required. @pre USE_X509 */ #define USE_FULL_CERT_PARSE/**< @pre USE_CERT_PARSE */ /**< Support extra distinguished name attributes that SHOULD be supported according to RFC 5280. */ //#define USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD @@ -205,7 +206,9 @@ Various PKCS standards support */ #define USE_PRIVATE_KEY_PARSING -//#define USE_PKCS5 /**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +#define USE_PKCS5/**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +/**< Enable PBKDF1 in priv key PEM encryption. @pre USE_PKCS5 and @pre USE_MD5. @security Not recommended. */ +#define USE_PBKDF1 #define USE_PKCS8/* Alternative private key storage format */ #define USE_PKCS12/**< @pre USE_PKCS8 */ #define USE_PKCS1_OAEP/* OAEP padding algorithm */ diff --git a/configs/rsaonly/cryptoConfig.h b/configs/rsaonly/cryptoConfig.h index 6f75395..41fbbfb 100644 --- a/configs/rsaonly/cryptoConfig.h +++ b/configs/rsaonly/cryptoConfig.h @@ -76,7 +76,7 @@ //#define USE_ECC //#define USE_DH /**< @note Enable verification of DSA signatures in certificate validation. - Works only when using the CL/SL library. */ + Works only when using the CL/SL library. @pre USE_CERT_PARSE. */ //#define USE_DSA_VERIFY /******************************************************************************/ @@ -136,7 +136,8 @@ @security MD5 is deprecated, but still required in combination with SHA-1 for TLS handshakes before TLS 1.2, meaning that the strength is at least - that of SHA-1 in this usage. The only other usage of MD5 by TLS is for + that of SHA-1 in this usage. The define USE_MD5SHA1 can be used to enable + MD5 only for this purpose. The only other usage of MD5 by TLS is for certificate signatures and MD5 based cipher suites. Both of which are disabled at compile time by default. @@ -167,7 +168,7 @@ */ #define USE_MD5 #define USE_MD5SHA1/* Required for < TLS 1.2 Handshake */ -#define USE_HMAC_MD5/* TODO currently needed for prf */ +#define USE_HMAC_MD5 /** @security MD2 is considered insecure, but is sometimes used for @@ -185,8 +186,8 @@ X.509 Certificates/PKI */ #define USE_BASE64_DECODE -#define USE_X509 -#define USE_CERT_PARSE/**< Usually required. @pre USE_X509 */ +#define USE_X509/**< Enable minimal X.509 support. */ +#define USE_CERT_PARSE/**< Enable TBSCertificate parsing. Usually required. @pre USE_X509 */ #define USE_FULL_CERT_PARSE/**< @pre USE_CERT_PARSE */ /**< Support extra distinguished name attributes that SHOULD be supported according to RFC 5280. */ //#define USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD @@ -205,7 +206,9 @@ Various PKCS standards support */ #define USE_PRIVATE_KEY_PARSING -//#define USE_PKCS5 /**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +#define USE_PKCS5/**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +/**< Enable PBKDF1 in priv key PEM encryption. @pre USE_PKCS5 and @pre USE_MD5. @security Not recommended. */ +#define USE_PBKDF1 #define USE_PKCS8/* Alternative private key storage format */ #define USE_PKCS12/**< @pre USE_PKCS8 */ #define USE_PKCS1_OAEP/* OAEP padding algorithm */ diff --git a/configs/tls/cryptoConfig.h b/configs/tls/cryptoConfig.h index 78e41eb..a42fe38 100644 --- a/configs/tls/cryptoConfig.h +++ b/configs/tls/cryptoConfig.h @@ -76,7 +76,7 @@ #define USE_ECC //#define USE_DH /**< @note Enable verification of DSA signatures in certificate validation. - Works only when using the CL/SL library. */ + Works only when using the CL/SL library. @pre USE_CERT_PARSE. */ //#define USE_DSA_VERIFY /******************************************************************************/ @@ -136,7 +136,8 @@ @security MD5 is deprecated, but still required in combination with SHA-1 for TLS handshakes before TLS 1.2, meaning that the strength is at least - that of SHA-1 in this usage. The only other usage of MD5 by TLS is for + that of SHA-1 in this usage. The define USE_MD5SHA1 can be used to enable + MD5 only for this purpose. The only other usage of MD5 by TLS is for certificate signatures and MD5 based cipher suites. Both of which are disabled at compile time by default. @@ -167,7 +168,7 @@ */ #define USE_MD5 #define USE_MD5SHA1/* Required for < TLS 1.2 Handshake */ -#define USE_HMAC_MD5/* TODO currently needed for prf */ +#define USE_HMAC_MD5 /** @security MD2 is considered insecure, but is sometimes used for @@ -185,8 +186,8 @@ X.509 Certificates/PKI */ #define USE_BASE64_DECODE -#define USE_X509 -#define USE_CERT_PARSE/**< Usually required. @pre USE_X509 */ +#define USE_X509/**< Enable minimal X.509 support. */ +#define USE_CERT_PARSE/**< Enable TBSCertificate parsing. Usually required. @pre USE_X509 */ #define USE_FULL_CERT_PARSE/**< @pre USE_CERT_PARSE */ /**< Support extra distinguished name attributes that SHOULD be supported according to RFC 5280. */ //#define USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD @@ -205,7 +206,9 @@ Various PKCS standards support */ #define USE_PRIVATE_KEY_PARSING -//#define USE_PKCS5 /**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +#define USE_PKCS5/**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +/**< Enable PBKDF1 in priv key PEM encryption. @pre USE_PKCS5 and @pre USE_MD5. @security Not recommended. */ +#define USE_PBKDF1 #define USE_PKCS8/* Alternative private key storage format */ #define USE_PKCS12/**< @pre USE_PKCS8 */ #define USE_PKCS1_OAEP/* OAEP padding algorithm */ diff --git a/core/coreApi.h b/core/coreApi.h index a1fa246..90714b2 100644 --- a/core/coreApi.h +++ b/core/coreApi.h @@ -197,11 +197,50 @@ extern psPool_t * const psStaticAllocationsPool; #include /******************************************************************************/ +/* struct tm is standard for representing broken-down time in C89, C99 and + POSIX.1 standards. The psBrokenDownTime_t is defined as an alias for + struct tm for compatibility with possible non-standard compliant targets. */ +typedef struct tm psBrokenDownTime_t; +/* time_t is a standard type for representing calendar time as a counter in + C89, C99. + */ +typedef time_t psTimeSeconds_t; + PSPUBLIC int32 psCoreOpen(const char *config); PSPUBLIC void psCoreClose(void); PSPUBLIC void psBurnStack(uint32 len); PSPUBLIC int32 memcmpct(const void *s1, const void *s2, size_t len); +PSPUBLIC void psFreeAndClear(void *ptrptr, psPool_t *pool); + +/******************************************************************************/ +/* + Public interface to functionality defined by functions in C89/C99 standards. + These function may be substituted with OS/psdep.c in nonstandard + systems. + + Return broken-down time similar to gmtime(&time(NULL)). The function allows + offset in seconds. +*/ +PSPUBLIC int32 psGetBrokenDownGMTime(psBrokenDownTime_t *t, + int offset); +/* Add specified value to broken down time. */ +PSPUBLIC int32 psBrokenDownTimeAdd(psBrokenDownTime_t *res, int32 offset); +#define PS_BROKENDOWN_TIME_STR_LEN 16 /* Good until year 9999. */ +PSPUBLIC int32 psBrokenDownTimeStr(const psBrokenDownTime_t *t1, + char (*string)[PS_BROKENDOWN_TIME_STR_LEN]); +#define PS_BROKENDOWN_TIME_IMPORT_STRICT_ZULU 1 /* Require Z as timezone. */ +#define PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR 2 /* Use two digit year for + range 1950-2049. */ +PSPUBLIC int32 psBrokenDownTimeImportSeconds(psBrokenDownTime_t *t, + psTimeSeconds_t s); +PSPUBLIC int32 psBrokenDownTimeImport( + psBrokenDownTime_t *t, + const char *string, size_t time_string_len, + unsigned int opts); +PSPUBLIC int psBrokenDownTimeCmp(const psBrokenDownTime_t *t1, + const psBrokenDownTime_t *t2); + /******************************************************************************/ /* Public interface to OS-dependant core functionality @@ -245,6 +284,51 @@ extern int32 psParseList(psPool_t *pool, char *list, const char separator, psList_t **items); extern void psFreeList(psList_t *list, psPool_t *pool); +/* Identifiers to describe type of string contained in char or + unsigned char array. */ +typedef enum { + /* Note: The values intentionally match ASN.1 BER/DER string type tags. */ + PS_STRING_UTF8_STRING = 12, + PS_STRING_NUMERIC_STRING = 18, + PS_STRING_PRINTABLE_STRING = 19, + PS_STRING_TELETEX_STRING = 20, + PS_STRING_VIDEOTEX_STRING = 21, + PS_STRING_IA5_STRING = 22, + PS_STRING_GRAPHIC_STRING = 25, + PS_STRING_VISIBLE_STRING = 26, + PS_STRING_GENERAL_STRING = 27, + PS_STRING_UNIVERSAL_STRING = 28, + PS_STRING_CHARACTER_STRING = 29, + PS_STRING_BMP_STRING = 30, + PS_STRING_CHAR_STRING = 256, /* Input is represented as C string. */ + PS_STRING_WCHAR_STRING = 257, /* Input is represented as wchar_t string. */ +} psStringType_t; + +/* Option for strictly checking input to UTF8 String. + The option is not currently implemented, and the function + psGetUtf8String() will always fail if you attempt to use the option. */ +#define PS_STRING_STRICT 1 +/* Uses sequence \0\0 as terminator for string. */ +#define PS_STRING_DUAL_NIL 2 + +/******************************************************************************/ +/* + Helper function for usual string conversions. + The current version allows conversion of + PS_STRING_NUMERIC_STRING, PS_STRING_PRINTABLE_STRING, PS_STRING_BMP_STRING + to UTF-8. In case conversion succeeds with PS_SUCCESS, *output will + point to a newly allocated string. The allocated string needs to be freed + with psFree(). The string will have terminating \0. + *output_len will be written string length not counting terminating \0. + output_len can be provided as NULL if user wants to use functions like + strlen() to obtain length of the string instead. +*/ +PSPUBLIC int32 psToUtf8String(psPool_t *pool, + const unsigned char *input, size_t input_len, + psStringType_t input_type, + unsigned char **output, size_t *output_len, + int opts); + /******************************************************************************/ /* Statistics helpers diff --git a/core/corelib.c b/core/corelib.c index 642fcad..d648a15 100644 --- a/core/corelib.c +++ b/core/corelib.c @@ -34,6 +34,12 @@ #include "coreApi.h" +#ifdef USE_MULTITHREADING +/* A mutex for concurrency control of functions implemented in this file. + Obvious exception are psCoreOpen() and psCoreClose(). */ +static psMutex_t corelibMutex; +#endif /* USE_MULTITHREADING */ + /******************************************************************************/ /* Open (initialize) the Core module @@ -73,6 +79,13 @@ int32 psCoreOpen(const char *config) osdepTimeClose(); return PS_FAILURE; } + if (psCreateMutex(&corelibMutex, 0) < 0) { + psTraceCore("psCreateMutex failed\n"); + osdepMutexClose(); + osdepEntropyClose(); + osdepTimeClose(); + return PS_FAILURE; + } #endif /* USE_MULTITHREADING */ return PS_SUCCESS; @@ -85,6 +98,7 @@ void psCoreClose(void) *g_config = 'N'; #ifdef USE_MULTITHREADING + psDestroyMutex(&corelibMutex); osdepMutexClose(); #endif /* USE_MULTITHREADING */ @@ -325,5 +339,470 @@ void psFreeAndClear(void *ptrptr, psPool_t *pool) } } +#if defined __unix__ || defined __unix || (defined (__APPLE__) && defined (__MACH__)) +#include /* Possibly provides _POSIX_VERSION. */ +/* 32-bit Unix machines may need workaround for Year 2038. + 64-bit Unix machines generally use large enough time_t. */ +#if !defined __LP64__ && !defined __ILP64__ +#define USE_UNIX_Y2038_WORKAROUND 1 +#endif +#endif /* __unix__ */ + +#ifdef _POSIX_VERSION +#define USE_GMTIME_R /* On posix systems, we use gmtime_r() */ +#endif /* _POSIX_VERSION */ + +/******************************************************************************/ +/* + Get broken-down time, similar to time returned by gmtime(), but avoiding + the race condition. The function only applies offset if it does not cause + overflow. +*/ +PSPUBLIC int32 psBrokenDownTimeImportSeconds(psBrokenDownTime_t *t, + psTimeSeconds_t s) +{ + int32 ret = PS_FAILURE; + struct tm *tm; + time_t time = s; + +#ifdef USE_GMTIME_R + /* Note: This command assumes psBrokenDownTime_t and struct tm use + exactly the same representation. If you optimize storage space of + psBrokenDownTime_t, then transfer each field separately. */ + tm = gmtime_r(&time, t); + if (tm != NULL) { + ret = PS_SUCCESS; + } +#else + /* Use mutex to lock. */ + psLockMutex(&corelibMutex); + tm = gmtime(&time); + if (tm) { + /* Note: This command assumes psBrokenDownTime_t and struct tm use + exactly the same representation. If you optimize storage space of + psBrokenDownTime_t, then transfer each field separately. */ + memcpy(t, tm, sizeof(*t)); + ret = PS_SUCCESS; + } + psUnlockMutex(&corelibMutex); +#endif + +#ifdef USE_UNIX_Y2038_WORKAROUND + /* Workaround for time_t overflow in 2038 on 32-bit Linux/Unix: */ + if (time < 0 && t->tm_year < 70) { + /* Overflow of dat has occurred. Fix the date, using + psBrokenDownTimeAdd(). This may possibly result in an estimate + because the computation here does not know of details like + leap seconds assigned in future. The result should be precise to + few seconds. */ + /* Note: Adjustment in three parts, because adjustment is too large + to be processed at once. + Note: 0x100000000 == 883612800 * 4 + 760516096. */ + (void)psBrokenDownTimeAdd(t, 883612800 * 2); + (void)psBrokenDownTimeAdd(t, 883612800 * 2); + (void)psBrokenDownTimeAdd(t, 760516096); + } +#endif /* USE_UNIX_Y2038_WORKAROUND */ + return ret; +} + +/* + Get broken-down time, similar to time returned by gmtime(), but avoiding + the race condition. The function only applies offset if it does not cause + overflow. +*/ +PSPUBLIC int32 psGetBrokenDownGMTime(psBrokenDownTime_t *t, int offset) +{ + int32 ret; + time_t current_time; + psTimeSeconds_t offseted_time; + + current_time = time(NULL); + if (current_time == ((time_t) -1)) { + return PS_FAILURE; + } + + /* Handle negative offsets here. */ + offseted_time = ((psTimeSeconds_t) current_time) + offset; + /* In case of overflow or positive offset, use time without offset. */ + if ((offset < 0 && offseted_time > current_time) || (offset > 0)) { + offseted_time = current_time; + } + + ret = psBrokenDownTimeImportSeconds(t, offseted_time); + /* Handle positive offsets here. */ + if (ret == PS_SUCCESS && offset > 0) { + ret = psBrokenDownTimeAdd(t, offset); + } + return ret; +} + +/* Compute number of days in month. */ +static int mdays(const psBrokenDownTime_t *t) +{ + static unsigned char days_tab[] = { + /* Jan */ 31, /* Most Feb */ 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + unsigned char days; + + if (t->tm_mon > 11) + return -1; + days = days_tab[t->tm_mon]; + if (days == 28) { + /* Note: This computation does not consider possible corrections once + every 3200 years. */ + int year = t->tm_year + 1900; + int is_leap_year = (year % 4) == 0 && + ((year % 100) != 0 || (year % 400) == 0); + days += is_leap_year; + } + return days; +} + +/******************************************************************************/ +/* + Compute broken-down time, with specified offset. The initial broken + down time t must have been previously initialized. This function only + needs to support positive offset (including 0). +*/ +PSPUBLIC int32 psBrokenDownTimeAdd(psBrokenDownTime_t *res, int32 offset) +{ + if (offset < 0) + return PS_FAILURE; + + /* Quick path for multiples of 28 years. */ + while(offset > 883612800) { + /* Quick addition of exactly 28 years (the cycle of Gregorian calendar, + 7 * 4 * 365.25 * 24 * 60 * 60 seconds). */ + offset -= 883612800; + res->tm_year += 28; + } + + if (offset == 0) + return PS_SUCCESS; + + /* Note: this function is approximate in presence of leap seconds. */ + res->tm_sec += offset; + if (res->tm_sec >= 60) { + res->tm_min += res->tm_sec / 60; + res->tm_sec %= 60; + } + if (res->tm_min >= 60) { + res->tm_hour += res->tm_min / 60; + res->tm_min %= 60; + } + if (res->tm_hour >= 24) { + res->tm_mday += res->tm_hour / 24; + res->tm_wday += res->tm_hour / 24; + res->tm_wday %= 7; + res->tm_hour %= 24; + } + /* Do month days, months & years as a loop. */ + while (res->tm_mday > mdays(res)) { + res->tm_mday -= mdays(res); + res->tm_mon += 1; + if (res->tm_mon > 11) { + res->tm_mon -= 12; + res->tm_year ++; + } + /* Note: tm_yday is not updated. */ + res->tm_hour %= 60; + } + return PS_SUCCESS; +} + +/******************************************************************************/ +/* + Format BrokenDown Time String with 4 digit year. + The string format will be "YYYYMMDDHHMMSSZ". Z and NIL are included. +*/ +PSPUBLIC int32 psBrokenDownTimeStr(const psBrokenDownTime_t *t, + char (*string)[PS_BROKENDOWN_TIME_STR_LEN]) +{ + size_t len = strftime(*string, PS_BROKENDOWN_TIME_STR_LEN, + "%Y%m%d%H%M%SZ", t); + return len == PS_BROKENDOWN_TIME_STR_LEN - 1 ? PS_SUCCESS : PS_FAILURE; +} + +/* Helper function to read specified amount of digits. + The number read shall be within boundaries. On parse errors function returns + (unsigned) -1, otherwise the parsed number. */ +static unsigned parse_digits( + const unsigned char **c_p, + unsigned digits, unsigned minimum, unsigned maximum) +{ + const unsigned char *c = *c_p; + unsigned result = 0; + + while(digits) { + if (*c < '0' || *c > '9') + return (unsigned) -1; + result *= 10; + result += *c - '0'; + c++; + digits--; + } + + *c_p = c; + + if (result < minimum || result > maximum) + return (unsigned) -1; + + return result; +} + +/******************************************************************************/ +/** + Verify a string has nearly valid date range format and length, + and return it in broken-down time format. + */ +static unsigned char parsedate_zulu(const unsigned char *p, + unsigned int time_len, + unsigned int year_len, + psBrokenDownTime_t *target, + int strict) +{ + unsigned year, month, mday, hour, min, sec; + const unsigned char *c = p; + psBrokenDownTime_t check_only; + + if (!target) + /* Use check_only as target. */ + target = &check_only; + + /* Zeroize all fields as some systems have extra fields + in struct tm. */ + memset(target, 0, sizeof(*target)); + + if (year_len == 4) { + /* Format shall be YYYYMMDDHHMMSSZ (according to RFC 5280). */ + if (time_len != 15 && strict) + return 0; + /* Flexible: allow Z to be replaced with anything. */ + if (time_len < 14 && !strict) + return 0; + year = parse_digits(&c, 4, 1900, 2999); + } else if (year_len == 2) { + /* Format shall be YYMMDDHHMMSSZ (according to RFC 5280). */ + if (time_len != 13 && strict) + return 0; + if (time_len < 12 && !strict) + return 0; + year = parse_digits(&c, 2, 0, 99); + } else { + return 0; + } + + if (year == (unsigned) -1) + return 0; + + month = parse_digits(&c, 2, 1, 12); + if (month == (unsigned) -1) + return 0; + + mday = parse_digits(&c, 2, 1, 31); + if (mday == (unsigned) -1) + return 0; + + hour = parse_digits(&c, 2, 0, 23); + if (hour == (unsigned) -1) + return 0; + + min = parse_digits(&c, 2, 0, 59); + if (min == (unsigned) -1) + return 0; + + /* This allows up-to 1 leap second. + (Note: could check that leap second only occurs at 23:59:60 on + end of Jun 30 or Dec 31 (such as on 31 Dec 2016 23:59:60), but + rules for insertion of leap seconds may change. */ + sec = parse_digits(&c, 2, 0, 60); + if (sec == (unsigned) -1) + return 0; + + /* Require all times in X.509 materials to be Zulu time, as is correct + according to RFC 5280. */ + if (strict && *c != 'Z') + return 0; + else { + /* Ignore time zone. The time zone shall be Zulu according to RFC 5280, + for X.509 certificates, CRL, OCSP etc. These times will be matched + exactly. However, some old systems may use certificates with some + other time zone. When handling those, the times will not be handled + exactly, but the inaccuracy will be within a day. */ + } + + /* Convert 2 or 4 digit year to tm format (year after 1900). + Two digit years are interpreted according to RFC 5280. */ + if (year < 50) + year += 100; + else if (year >= 1900) + year -= 1900; + else if (year >= 100) + /* years 100-1900 cannot be represented in psBrokenDownTime_t. */ + return 0; + else { + /* Two digit year 50-99 is already correct. */ + } + + target->tm_year = (int) year; + target->tm_mon = (int) month - 1; + target->tm_mday = (int) mday; + target->tm_hour = (int) hour; + target->tm_min = (int) min; + target->tm_sec = (int) sec; + /* Note: target->tm_wday and target->tm_yday are not set. */ + if (target->tm_mday > mdays(target)) { + /* No such day in this month. */ + memset(target, 0, sizeof(*target)); + return 0; + } + return 1; +} + +/******************************************************************************/ +/* + Import BrokenDown Time from String format. Number of digits in year + can be provided via an option. The string format recommended is + "YYYYMMDDHHMMSSZ". + This function only supports Zulu time, any other time zone will be ignored. +*/ +PSPUBLIC int32 psBrokenDownTimeImport( + psBrokenDownTime_t *t, + const char *string, size_t time_string_len, + unsigned int opts) +{ + unsigned char res; + /* Reject very long strings as illegal. */ + if (time_string_len > 255) + return PS_FAILURE; + + res = parsedate_zulu((const unsigned char *)string, + (unsigned int) time_string_len, + (opts & PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR) ? + 2 : 4, t, + (opts & PS_BROKENDOWN_TIME_IMPORT_STRICT_ZULU)); + + return res ? PS_SUCCESS : PS_FAILURE; +} + +/******************************************************************************/ +/* + Compute broken-down times, returning <0, 0 or >0 according to t1 being + smaller, equal or greater than t2. +*/ +PSPUBLIC int psBrokenDownTimeCmp(const psBrokenDownTime_t *t1, + const psBrokenDownTime_t *t2) +{ + char s1[PS_BROKENDOWN_TIME_STR_LEN] = { '!', 0 }; + char s2[PS_BROKENDOWN_TIME_STR_LEN] = { 0 }; + + /* The dates are represented using YYYYMMDDHHMMSSZ for comparison. + I.e. comparison ignores tm_wday, tm_yday, and tm_isdst. */ + (void) psBrokenDownTimeStr(t1, &s1); + (void) psBrokenDownTimeStr(t2, &s2); + /* If you wish to debug time comparisons, you can enable next lines. */ + /* _psTraceStr("Comparing t1: %s against ", s1); */ + /* _psTraceStr("t2: %s ", s2); */ + /* _psTraceInt("got: %d\n", memcmp(s1, s2, sizeof(s1))); */ + return memcmp(s1, s2, sizeof(s1)); +} + +/******************************************************************************/ +/* + Helper function for String conversion. +*/ +PSPUBLIC int32 psToUtf8String(psPool_t *pool, + const unsigned char *input, size_t input_len, + psStringType_t input_type, + unsigned char **output, size_t *output_len, + int opts) +{ + int32 err; + psParseBuf_t in; + psDynBuf_t out; + size_t ignored_size; + int clen = 1; + + if ((opts & ~PS_STRING_DUAL_NIL) != 0) + return PS_UNSUPPORTED_FAIL; + + switch(input_type) { + case PS_STRING_NUMERIC_STRING: + case PS_STRING_PRINTABLE_STRING: + /* These are subsets of ASCII. */ + break; + case PS_STRING_BMP_STRING: + /* UCS2 characters. */ + clen = 2; + break; + default: + return PS_UNSUPPORTED_FAIL; + } + + /* Sequence of 16-bit characters has to have even length. */ + if (clen == 2 && (input_len & 1) > 0) { + return PS_FAILURE; + } + + err = psParseBufFromStaticData(&in, input, input_len); + if (err != PS_SUCCESS) + return err; + + /* Create dynamic buffer with initial size estimate being the same + than input + termination character(s). */ + err = psDynBufInit(pool, &out, input_len + 2) ? PS_SUCCESS : PS_MEM_FAIL; + if (err != PS_SUCCESS) + return err; + + if (clen == 1) { + while(psParseCanRead(&in, 1)) { + int8_t chr = (int8_t) *in.buf.start; + if (chr >= 1) { + (void)psDynBufAppendChar(&out, (char) chr); + } else { + /* non-ASCII character (eight bit set) or \0. */ + err = PS_LIMIT_FAIL; + } + psParseBufSkipBytes(&in, (unsigned char *) &chr, 1); + } + } else /* clen == 2 */ { + while(psParseCanRead(&in, 2)) { + unsigned char a[2]; + uint16_t chr; + memcpy(a, in.buf.start, 2); + chr = a[0]; + chr <<= 8; + chr |= a[1]; + if (chr != 0 && (chr < 0xd800 || chr > 0xdfff)) { + /* ASCII */ + (void)psDynBufAppendUtf8(&out, chr); + } else { + /* surrogate pair or \0. These are invalid code points BMP. */ + err = PS_LIMIT_FAIL; + } + psParseBufSkipBytes(&in, a, 2); + } + } + + if (output_len == NULL) + output_len = &ignored_size; + + /* Append terminating \0 or \0\0. */ + psDynBufAppendChar(&out, 0); + if ((opts & PS_STRING_DUAL_NIL) != 0) + psDynBufAppendChar(&out, 0); + + if (err == PS_SUCCESS) { + *output = psDynBufDetach(&out, output_len); + *output_len -= (opts & PS_STRING_DUAL_NIL) ? 2 : 1; + if (*output == NULL) + return PS_MEM_FAIL; + } else { + psDynBufUninit(&out); + } + return err; +} + /******************************************************************************/ diff --git a/core/memset_s.c b/core/memset_s.c index d44cf4f..8cb9fc5 100644 --- a/core/memset_s.c +++ b/core/memset_s.c @@ -54,9 +54,15 @@ #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC push_options #pragma GCC optimize("O0") -#define NO_OPTIM __attribute__((noinline)) __attribute__((optimize("O0"))) +#ifdef __clang__ +#define NO_OPTIM \ + __attribute__((__noinline__)) __attribute__((__optnone__)) #else -#define NO_OPTIM +#define NO_OPTIM \ + __attribute__((__noinline__)) __attribute__((__optimize__("O0"))) +#endif +#else +#define NO_OPTIM /* Unrecognized compiler or not optimizing. */ #endif #include diff --git a/core/psbuf.c b/core/psbuf.c index a5454a3..6f22fb7 100644 --- a/core/psbuf.c +++ b/core/psbuf.c @@ -307,6 +307,48 @@ void *psDynBufAppendSize(psDynBuf_t *db, size_t sz) return loc; } +void *psDynBufAppendUtf8(psDynBuf_t *db, int chr) +{ + unsigned char *enc; + unsigned int ch = (unsigned int) chr; + /* Do not encode characters outside valid UTF-8 range. */ + if (ch > 0x1FFFF) { + db->err++; + return NULL; + } + if (ch < 128) { + enc = psDynBufAppendSize(db, 1); + if (enc) + *enc = (unsigned char) ch; + } else if (ch <= 0x7FF) { + /* Two byte encoding. */ + enc = psDynBufAppendSize(db, 2); + if (enc) { + enc[0] = (unsigned char) (0xC0 | (ch >> 6)); + enc[1] = (unsigned char) (0x80 | (ch & 63)); + } + } else if (ch <= 0xffff) { + /* Three byte encoding. */ + enc = psDynBufAppendSize(db, 3); + if (enc) { + enc[0] = (unsigned char) (0xE0 | (ch >> 12)); + enc[1] = (unsigned char) (0x80 | ((ch >> 6) & 63)); + enc[2] = (unsigned char) (0x80 | (ch & 63)); + } + } else { + /* Four byte encoding. */ + enc = psDynBufAppendSize(db, 4); + if (enc) { + enc[0] = (unsigned char) (0xF0 | (ch >> 18)); + enc[1] = (unsigned char) (0x80 | ((ch >> 12) & 63)); + enc[2] = (unsigned char) (0x80 | ((ch >> 6) & 63)); + enc[3] = (unsigned char) (0x80 | (ch & 63)); + } + } + return enc; +} + + void psDynBufReservePrepend(psDynBuf_t *db, size_t sz) { /* This function only performs action if nothing has been pushed. diff --git a/core/psbuf.h b/core/psbuf.h index 80a0a54..928b16a 100644 --- a/core/psbuf.h +++ b/core/psbuf.h @@ -91,6 +91,8 @@ static __inline void *psDynBufAppendChar(psDynBuf_t *db, char ch) return loc; } +void *psDynBufAppendUtf8(psDynBuf_t *db, int chr); + static __inline void *psDynBufPrependChar(psDynBuf_t *db, char ch) { void *loc = psDynBufPrependSize(db, 1); diff --git a/crypto/cryptoApi.h b/crypto/cryptoApi.h index 9d348c1..fd3ad33 100644 --- a/crypto/cryptoApi.h +++ b/crypto/cryptoApi.h @@ -63,7 +63,7 @@ extern "C" { #define PS_CERT_AUTH_FAIL_BC -32 /* BasicConstraint failure */ #define PS_CERT_AUTH_FAIL_DN -33 /* DistinguishedName failure */ #define PS_CERT_AUTH_FAIL_SIG -34 /* Signature validation failure */ -#define PS_CERT_AUTH_FAIL_REVOKED -35 /* Revoked via CRL */ +#define PS_CERT_AUTH_FAIL_REVOKED -35 /* Revoked via CRL or OCSP */ #define PS_CERT_AUTH_FAIL -36 /* Generic cert auth fail */ #define PS_CERT_AUTH_FAIL_EXTENSION -37 /* extension permission problem */ #define PS_CERT_AUTH_FAIL_PATH_LEN -38 /* pathLen exceeded */ @@ -267,6 +267,10 @@ PSPUBLIC void psDes3Clear(psDes3_t *ctx); */ #ifdef USE_MD5 /******************************************************************************/ +static __inline void psMd5PreInit(psMd5_t *md5) +{ + /* Nothing to pre-initialize for native crypto. */ +} PSPUBLIC int32_t psMd5Init(psMd5_t *md5); PSPUBLIC void psMd5Update(psMd5_t *md5, const unsigned char *buf, uint32_t len); PSPUBLIC void psMd5Final(psMd5_t *md, unsigned char hash[MD5_HASHLEN]); @@ -495,7 +499,7 @@ PSPUBLIC int32 psPkcs12Parse(psPool_t *pool, psX509Cert_t **cert, /* PKCS#5 PBKDF v1 and v2 key generation */ -PSPUBLIC void pkcs5pbkdf1(unsigned char *pass, uint32 passlen, +PSPUBLIC int32_t pkcs5pbkdf1(unsigned char *pass, uint32 passlen, unsigned char *salt, int32 iter, unsigned char *key); PSPUBLIC void pkcs5pbkdf2(unsigned char *password, uint32 pLen, unsigned char *salt, uint32 sLen, int32 rounds, @@ -724,6 +728,19 @@ PSPUBLIC int32_t psInitPrng(psRandom_t *ctx, void *userPtr); PSPUBLIC int32_t psGetPrng(psRandom_t *ctx, unsigned char *bytes, uint16_t size, void *userPtr); +#ifdef USE_YARROW +/******************************************************************************/ +PSPUBLIC int32 psYarrowStart(psYarrow_t *ctx); +PSPUBLIC int32 psYarrowAddEntropy(unsigned char *in, uint32 inlen, + psYarrow_t *prng); +PSPUBLIC int32 psYarrowReseed(psYarrow_t *ctx); +PSPUBLIC uint32 psYarrowRead(unsigned char *out, uint32 outlen, psYarrow_t *cx); +PSPUBLIC int32 psYarrowDone(psYarrow_t *ctx); +PSPUBLIC int32 psYarrowExport(unsigned char *out, uint32 *outlen, + psYarrow_t *ctx); +PSPUBLIC int32 psYarrowImport(unsigned char *in, uint32 inlen, psYarrow_t *ctx); +#endif /* USE_YARROW */ + /******************************************************************************/ /* Deprecated Algorithms @@ -778,6 +795,10 @@ PSPUBLIC int32_t psMd4Final(psMd4_t *md, unsigned char *hash); #ifdef USE_MD2 /******************************************************************************/ +static __inline void psMd2PreInit(psMd2_t *md2) +{ + /* Nothing to pre-initialize for native crypto. */ +} PSPUBLIC void psMd2Init(psMd2_t *md); PSPUBLIC int32_t psMd2Update(psMd2_t *md, const unsigned char *buf, uint32_t len); diff --git a/crypto/cryptoCheck.h b/crypto/cryptoCheck.h index 1479d0d..e5f5dd7 100644 --- a/crypto/cryptoCheck.h +++ b/crypto/cryptoCheck.h @@ -47,9 +47,17 @@ #endif #endif +#ifdef USE_PBKDF1 + #ifndef USE_PKCS5 + #error "Enable USE_PKCS5 in cryptoConfig.h for PKBDF1 support" + #endif +#endif + #ifdef USE_PKCS5 - #ifndef USE_MD5 - #error "Enable USE_MD5 in cryptoConfig.h for PKCS5 support" + #ifdef USE_PBKDF1 + #ifndef USE_MD5 + #error "Enable USE_MD5 in cryptoConfig.h for PBKDF1 support" + #endif #endif #ifndef USE_3DES #error "Enable USE_3DES in cryptoConfig.h for PKCS5 support" diff --git a/crypto/cryptoConfig.h b/crypto/cryptoConfig.h index 3a07dc4..f822e75 100644 --- a/crypto/cryptoConfig.h +++ b/crypto/cryptoConfig.h @@ -76,7 +76,7 @@ #define USE_ECC #define USE_DH /**< @note Enable verification of DSA signatures in certificate validation. - Works only when using the CL/SL library. */ + Works only when using the CL/SL library. @pre USE_CERT_PARSE. */ //#define USE_DSA_VERIFY /******************************************************************************/ @@ -136,7 +136,8 @@ @security MD5 is deprecated, but still required in combination with SHA-1 for TLS handshakes before TLS 1.2, meaning that the strength is at least - that of SHA-1 in this usage. The only other usage of MD5 by TLS is for + that of SHA-1 in this usage. The define USE_MD5SHA1 can be used to enable + MD5 only for this purpose. The only other usage of MD5 by TLS is for certificate signatures and MD5 based cipher suites. Both of which are disabled at compile time by default. @@ -167,7 +168,7 @@ */ #define USE_MD5 #define USE_MD5SHA1/* Required for < TLS 1.2 Handshake */ -#define USE_HMAC_MD5/* TODO currently needed for prf */ +#define USE_HMAC_MD5 /** @security MD2 is considered insecure, but is sometimes used for @@ -185,8 +186,8 @@ X.509 Certificates/PKI */ #define USE_BASE64_DECODE -#define USE_X509 -#define USE_CERT_PARSE/**< Usually required. @pre USE_X509 */ +#define USE_X509/**< Enable minimal X.509 support. */ +#define USE_CERT_PARSE/**< Enable TBSCertificate parsing. Usually required. @pre USE_X509 */ #define USE_FULL_CERT_PARSE/**< @pre USE_CERT_PARSE */ /**< Support extra distinguished name attributes that SHOULD be supported according to RFC 5280. */ //#define USE_EXTRA_DN_ATTRIBUTES_RFC5280_SHOULD @@ -205,7 +206,9 @@ Various PKCS standards support */ #define USE_PRIVATE_KEY_PARSING -//#define USE_PKCS5 /**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +#define USE_PKCS5/**< v2.0 PBKDF encrypted priv keys. @pre USE_3DES */ +/**< Enable PBKDF1 in priv key PEM encryption. @pre USE_PKCS5 and @pre USE_MD5. @security Not recommended. */ +#define USE_PBKDF1 #define USE_PKCS8/* Alternative private key storage format */ #define USE_PKCS12/**< @pre USE_PKCS8 */ #define USE_PKCS1_OAEP/* OAEP padding algorithm */ diff --git a/crypto/cryptolib.h b/crypto/cryptolib.h index 959707e..aae524a 100644 --- a/crypto/cryptolib.h +++ b/crypto/cryptolib.h @@ -110,81 +110,231 @@ extern int32_t matrixCryptoGetPrngData(unsigned char *bytes, uint16_t size, /******************************************************************************/ /* - RFC 3279 OID + RFC 3279 OID and PKCS standards OIDs Matrix uses an oid summing mechanism to arrive at these defines. - The byte values of the OID are summed to produce a "relatively unique" int - - The duplicate defines do not pose a problem as long as they don't - exist in the same OID groupings + The byte values of the OID are summed and compared with OID database + entries to produce a unique numbers (assuming MATRIXSSL_NO_OID_DATABASE + is not set.) */ + +#ifdef MATRIXSSL_NO_OID_DATABASE +/* Without OID database, some entries will be duplicates. */ +#define OID_COLLISION 0 +#else +/* To prevent collisions, some oids are added a sufficient multiple of this + to make them unique. */ +#define OID_COLLISION 1024 + +/* Marking for OIDs that have not been discovered in the database. + The OIDs not discovered are guaranteed to be this value or larger. */ +#define OID_NOT_FOUND 32768 +#endif /* MATRIXSSL_NO_OID_DATABASE */ + /* Raw digest algorithms */ -#define OID_SHA1_ALG 88 -#define OID_SHA256_ALG 414 -#define OID_SHA384_ALG 415 -#define OID_SHA512_ALG 416 -#define OID_MD2_ALG 646 -#define OID_MD5_ALG 649 + +#define OID_SHA1_ALG_STR "1.3.14.3.2.26" +#define OID_SHA1_ALG 88 +#define OID_SHA1_ALG_HEX "\x06\x05\x2B\x0E\x03\x02\x1A" +#define OID_SHA256_ALG_STR "2.16.840.1.101.3.4.2.1" +#define OID_SHA256_ALG 414 +#define OID_SHA256_ALG_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01" +#define OID_SHA384_ALG_STR "2.16.840.1.101.3.4.2.2" +#define OID_SHA384_ALG 415 +#define OID_SHA384_ALG_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02" +#define OID_SHA512_ALG_STR "2.16.840.1.101.3.4.2.3" +#define OID_SHA512_ALG 416 +#define OID_SHA512_ALG_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03" +#define OID_MD2_ALG_STR "1.2.840.113549.2.2" +#define OID_MD2_ALG 646 +#define OID_MD2_ALG_HEX "\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02\x02" +#define OID_MD5_ALG_STR "1.2.840.113549.2.5" +#define OID_MD5_ALG 649 +#define OID_MD5_ALG_HEX "\x06\x08\x2A\x86\x48\x86\xF7\x0D\x02\x05" /* Signature algorithms */ -#define OID_MD2_RSA_SIG 646 -#define OID_MD5_RSA_SIG 648 /* 42.134.72.134.247.13.1.1.4 */ -#define OID_SHA1_RSA_SIG 649 /* 42.134.72.134.247.13.1.1.5 */ -#define OID_ID_MGF1 652 /* 42.134.72.134.247.13.1.1.8 */ -#define OID_RSASSA_PSS 654 /* 42.134.72.134.247.13.1.1.10 */ -#define OID_SHA256_RSA_SIG 655 /* 42.134.72.134.247.13.1.1.11 */ -#define OID_SHA384_RSA_SIG 656 /* 42.134.72.134.247.13.1.1.12 */ -#define OID_SHA512_RSA_SIG 657 /* 42.134.72.134.247.13.1.1.13 */ -#define OID_SHA1_DSA_SIG 517 /* 1.2.840.10040.4.3 */ -#define OID_SHA1_ECDSA_SIG 520 /* 42.134.72.206.61.4.1 */ -#define OID_SHA224_ECDSA_SIG 523 /* 42.134.72.206.61.4.3.1 */ -#define OID_SHA256_ECDSA_SIG 524 /* 42.134.72.206.61.4.3.2 */ -#define OID_SHA384_ECDSA_SIG 525 /* 42.134.72.206.61.4.3.3 */ -#define OID_SHA512_ECDSA_SIG 526 /* 42.134.72.206.61.4.3.4 */ +#define OID_MD2_RSA_SIG_STR "1.2.840.113549.1.1.2" +#define OID_MD2_RSA_SIG (646 + OID_COLLISION) +#define OID_MD2_RSA_SIG_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x02" +#define OID_MD5_RSA_SIG_STR "1.2.840.113549.1.1.4" +#define OID_MD5_RSA_SIG 648 +#define OID_MD5_RSA_SIG_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x04" +#define OID_SHA1_RSA_SIG_STR "1.2.840.113549.1.1.5" +#define OID_SHA1_RSA_SIG (649 + OID_COLLISION) +#define OID_SHA1_RSA_SIG_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x05" +#define OID_ID_MGF1_STR "1.2.840.113549.1.1.8" +#define OID_ID_MGF1 (652 + OID_COLLISION * 2) +#define OID_ID_MGF1_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x08" +#define OID_RSASSA_PSS_STR "1.2.840.113549.1.1.10" +#define OID_RSASSA_PSS (654 + OID_COLLISION) +#define OID_RSASSA_PSS_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0A" +#define OID_SHA256_RSA_SIG_STR "1.2.840.113549.1.1.11" +#define OID_SHA256_RSA_SIG (655 + OID_COLLISION) +#define OID_SHA256_RSA_SIG_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B" +#define OID_SHA384_RSA_SIG_STR "1.2.840.113549.1.1.12" +#define OID_SHA384_RSA_SIG (656 + OID_COLLISION) +#define OID_SHA384_RSA_SIG_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0C" +#define OID_SHA512_RSA_SIG_STR "1.2.840.113549.1.1.13" +#define OID_SHA512_RSA_SIG (657 + OID_COLLISION) +#define OID_SHA512_RSA_SIG_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0D" +#define OID_SHA1_DSA_SIG_STR "1.2.840.10040.4.3" +#define OID_SHA1_DSA_SIG 517 +#define OID_SHA1_DSA_SIG_HEX "\x06\x07\x2A\x86\x48\xCE\x38\x04\x03" +#define OID_SHA1_ECDSA_SIG_STR "1.2.840.10045.4.1" +#define OID_SHA1_ECDSA_SIG 520 +#define OID_SHA1_ECDSA_SIG_HEX "\x06\x07\x2A\x86\x48\xCE\x3D\x04\x01" +#define OID_SHA224_ECDSA_SIG_STR "1.2.840.10045.4.3.1" +#define OID_SHA224_ECDSA_SIG 523 +#define OID_SHA224_ECDSA_SIG_HEX "\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x01" +#define OID_SHA256_ECDSA_SIG_STR "1.2.840.10045.4.3.2" +#define OID_SHA256_ECDSA_SIG 524 +#define OID_SHA256_ECDSA_SIG_HEX "\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x02" +#define OID_SHA384_ECDSA_SIG_STR "1.2.840.10045.4.3.3" +#define OID_SHA384_ECDSA_SIG 525 +#define OID_SHA384_ECDSA_SIG_HEX "\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x03" +#define OID_SHA512_ECDSA_SIG_STR "1.2.840.10045.4.3.4" +#define OID_SHA512_ECDSA_SIG 526 +#define OID_SHA512_ECDSA_SIG_HEX "\x06\x08\x2A\x86\x48\xCE\x3D\x04\x03\x04" /* Public key algorithms */ -#define OID_RSA_KEY_ALG 645 -#define OID_DSA_KEY_ALG 515 /* 1.2.840.10040.4.1 */ -#define OID_ECDSA_KEY_ALG 518 /* 1.2.840.10045.2.1 */ +#define OID_RSA_KEY_ALG_STR "1.2.840.113549.1.1.1" +#define OID_RSA_KEY_ALG 645 +#define OID_RSA_KEY_ALG_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01" +#define OID_DSA_KEY_ALG_STR "1.2.840.10040.4.1" +#define OID_DSA_KEY_ALG 515 +#define OID_DSA_KEY_ALG_HEX "\x06\x07\x2A\x86\x48\xCE\x38\x04\x01" +#define OID_ECDSA_KEY_ALG_STR "1.2.840.10045.2.1" +#define OID_ECDSA_KEY_ALG 518 +#define OID_ECDSA_KEY_ALG_HEX "\x06\x07\x2A\x86\x48\xCE\x3D\x02\x01" /* Encryption algorithms */ -#define OID_DES_EDE3_CBC 652 /* 42.134.72.134.247.13.3.7 */ -#define OID_AES_128_CBC 414 /* 2.16.840.1.101.3.4.1.2 */ -#define OID_AES_128_WRAP 417 /* 2.16.840.1.101.3.4.1.5 */ -#define OID_AES_128_GCM 418 /* 2.16.840.1.101.3.4.1.6 */ -#define OID_AES_192_CBC 434 /* 2.16.840.1.101.3.4.1.22 */ -#define OID_AES_192_WRAP 437 /* 2.16.840.1.101.3.4.1.25 */ -#define OID_AES_192_GCM 438 /* 2.16.840.1.101.3.4.1.26 */ -#define OID_AES_256_CBC 454 /* 2.16.840.1.101.3.4.1.42 */ -#define OID_AES_256_WRAP 457 /* 2.16.840.1.101.3.4.1.45 */ -#define OID_AES_256_GCM 458 /* 2.16.840.1.101.3.4.1.46 */ +#define OID_DES_EDE3_CBC_STR "1.2.840.113549.3.7" +#define OID_DES_EDE3_CBC (652 + OID_COLLISION) +#define OID_DES_EDE3_CBC_HEX "\x06\x08\x2A\x86\x48\x86\xF7\x0D\x03\x07" -#define OID_AES_CMAC 612 /* 2.16.840.1.101.3.4.1.200 */ +#define OID_AES_128_CBC_STR "2.16.840.1.101.3.4.1.2" +#define OID_AES_128_CBC (414 + OID_COLLISION) +#define OID_AES_128_CBC_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x02" +#define OID_AES_128_WRAP_STR "2.16.840.1.101.3.4.1.5" +#define OID_AES_128_WRAP 417 +#define OID_AES_128_WRAP_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x05" +#define OID_AES_128_GCM_STR "2.16.840.1.101.3.4.1.6" +#define OID_AES_128_GCM 418 +#define OID_AES_128_GCM_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x06" +#define OID_AES_192_CBC_STR "2.16.840.1.101.3.4.1.22" +#define OID_AES_192_CBC 434 +#define OID_AES_192_CBC_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x16" +#define OID_AES_192_WRAP_STR "2.16.840.1.101.3.4.1.25" +#define OID_AES_192_WRAP 437 +#define OID_AES_192_WRAP_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x19" +#define OID_AES_192_GCM_STR "2.16.840.1.101.3.4.1.26" +#define OID_AES_192_GCM 438 +#define OID_AES_192_GCM_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x1A" +#define OID_AES_256_CBC_STR "2.16.840.1.101.3.4.1.42" +#define OID_AES_256_CBC 454 +#define OID_AES_256_CBC_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x2A" +#define OID_AES_256_WRAP_STR "2.16.840.1.101.3.4.1.45" +#define OID_AES_256_WRAP 457 +#define OID_AES_256_WRAP_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x2D" +#define OID_AES_256_GCM_STR "2.16.840.1.101.3.4.1.46" +#define OID_AES_256_GCM 458 +#define OID_AES_256_GCM_HEX "\x06\x09\x60\x86\x48\x01\x65\x03\x04\x01\x2E" -#define OID_AES_CBC_CMAC_128 143 -#define OID_AES_CBC_CMAC_192 144 -#define OID_AES_CBC_CMAC_256 145 +#define OID_AES_CMAC_STR "2.16.840.1.101.3.4.1.200_alt" +#define OID_AES_CMAC 612 +#define OID_AES_CMAC_HEX "\x06\x0A\x60\x86\x48\x01\x65\x03\x04\x01\xC8" -#define OID_AUTH_ENC_256_SUM 687 /* The RFC 6476 authEnc OID */ +#define OID_AES_CBC_CMAC_128_STR "0.4.0.127.0.7.1.1.1.2" +#define OID_AES_CBC_CMAC_128 143 +#define OID_AES_CBC_CMAC_128_HEX "\x06\x09\x04\x00\x7F\x00\x07\x01\x01\x01\x02" +#define OID_AES_CBC_CMAC_192_STR "0.4.0.127.0.7.1.1.1.3" +#define OID_AES_CBC_CMAC_192 144 +#define OID_AES_CBC_CMAC_192_HEX "\x06\x09\x04\x00\x7F\x00\x07\x01\x01\x01\x03" +#define OID_AES_CBC_CMAC_256_STR "0.4.0.127.0.7.1.1.1.4" +#define OID_AES_CBC_CMAC_256 145 +#define OID_AES_CBC_CMAC_256_HEX "\x06\x09\x04\x00\x7F\x00\x07\x01\x01\x01\x04" -#ifdef USE_PKCS5 -#define OID_PKCS_PBKDF2 660 /* 42.134.72.134.247.13.1.5.12 */ -#define OID_PKCS_PBES2 661 /* 42.134.72.134.247.13.1.5.13 */ -#endif /* USE_PKCS5 */ +#define OID_AUTH_ENC_256_SUM_STR "1.2.840.113549.1.9.16.3.16" +#define OID_AUTH_ENC_256_SUM 687 /* See RFC 6476 */ +#define OID_AUTH_ENC_256_SUM_HEX "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x09\x10\x03\x10" -#ifdef USE_PKCS12 -#define OID_PKCS_PBESHA128RC4 657 -#define OID_PKCS_PBESHA40RC4 658 -#define OID_PKCS_PBESHA3DES3 659 -#define OID_PKCS_PBESHA3DES2 660 /* warning: collision with pkcs5 */ -#define OID_PKCS_PBESHA128RC2 661 /* warning: collision with pkcs5 */ -#define OID_PKCS_PBESHA40RC2 662 +#define OID_PKCS_PBKDF2_STR "1.2.840.113549.1.5.12" +#define OID_PKCS_PBKDF2 (660 + OID_COLLISION) +#define OID_PKCS_PBKDF2_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0C" +#define OID_PKCS_PBES2_STR "1.2.840.113549.1.5.13" +#define OID_PKCS_PBES2 (661 + OID_COLLISION) +#define OID_PKCS_PBES2_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x05\x0D" + +#define OID_PKCS_PBESHA128RC4_STR "1.2.840.113549.1.12.1.1" +#define OID_PKCS_PBESHA128RC4 657 +#define OID_PKCS_PBESHA128RC4_HEX "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x01" +#define OID_PKCS_PBESHA40RC4_STR "1.2.840.113549.1.12.1.2" +#define OID_PKCS_PBESHA40RC4 658 +#define OID_PKCS_PBESHA40RC4_HEX "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x02" +#define OID_PKCS_PBESHA3DES3_STR "1.2.840.113549.1.12.1.3" +#define OID_PKCS_PBESHA3DES3 659 +#define OID_PKCS_PBESHA3DES3_HEX "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x03" +#define OID_PKCS_PBESHA2DES3_STR "1.2.840.113549.1.12.1.4" +#define OID_PKCS_PBESHA2DES3 660 +#define OID_PKCS_PBESHA2DES3_HEX "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x04" +#define OID_PKCS_PBESHA128RC2_STR "1.2.840.113549.1.12.1.5" +#define OID_PKCS_PBESHA128RC2 661 +#define OID_PKCS_PBESHA128RC2_HEX "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x05" +#define OID_PKCS_PBESHA40RC2_STR "1.2.840.113549.1.12.1.6" +#define OID_PKCS_PBESHA40RC2 662 +#define OID_PKCS_PBESHA40RC2_HEX "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x01\x06" + +#define OID_PKCS12_BAG_TYPE_KEY_STR "1.2.840.113549.1.12.10.1.1" +#define OID_PKCS12_BAG_TYPE_KEY 667 +#define OID_PKCS12_BAG_TYPE_KEY_HEX "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x01" +#define OID_PKCS12_BAG_TYPE_SHROUD_STR "1.2.840.113549.1.12.10.1.2" +#define OID_PKCS12_BAG_TYPE_SHROUD 668 +#define OID_PKCS12_BAG_TYPE_SHROUD_HEX "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x02" +#define OID_PKCS12_BAG_TYPE_CERT_STR "1.2.840.113549.1.12.10.1.3" +#define OID_PKCS12_BAG_TYPE_CERT 669 +#define OID_PKCS12_BAG_TYPE_CERT_HEX "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x03" +#define OID_PKCS12_BAG_TYPE_CRL_STR "1.2.840.113549.1.12.10.1.4" +#define OID_PKCS12_BAG_TYPE_CRL 670 +#define OID_PKCS12_BAG_TYPE_CRL_HEX "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x04" +#define OID_PKCS12_BAG_TYPE_SECRET_STR "1.2.840.113549.1.12.10.1.5" +#define OID_PKCS12_BAG_TYPE_SECRET 671 +#define OID_PKCS12_BAG_TYPE_SECRET_HEX "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x05" +#define OID_PKCS12_BAG_TYPE_SAFE_STR "1.2.840.113549.1.12.10.1.6" +#define OID_PKCS12_BAG_TYPE_SAFE 672 +#define OID_PKCS12_BAG_TYPE_SAFE_HEX "\x06\x0B\x2A\x86\x48\x86\xF7\x0D\x01\x0C\x0A\x01\x06" + +#define OID_PKCS9_CERT_TYPE_X509_STR "1.2.840.113549.1.9.22.1" +#define OID_PKCS9_CERT_TYPE_X509 675 +#define OID_PKCS9_CERT_TYPE_X509_HEX "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x09\x16\x01" +#define OID_PKCS9_CERT_TYPE_SDSI_STR "1.2.840.113549.1.9.22.2" +#define OID_PKCS9_CERT_TYPE_SDSI 676 +#define OID_PKCS9_CERT_TYPE_SDSI_HEX "\x06\x0A\x2A\x86\x48\x86\xF7\x0D\x01\x09\x16\x02" + +#define OID_PKCS7_DATA_STR "1.2.840.113549.1.7.1" +#define OID_PKCS7_DATA 651 +#define OID_PKCS7_DATA_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x01" +#define OID_PKCS7_SIGNED_DATA_STR "1.2.840.113549.1.7.2" +#define OID_PKCS7_SIGNED_DATA 652 +#define OID_PKCS7_SIGNED_DATA_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x02" +#define OID_PKCS7_ENVELOPED_DATA_STR "1.2.840.113549.1.7.3" +#define OID_PKCS7_ENVELOPED_DATA 653 +#define OID_PKCS7_ENVELOPED_DATA_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x03" +#define OID_PKCS7_SIGNED_ENVELOPED_DATA_STR "1.2.840.113549.1.7.4" +#define OID_PKCS7_SIGNED_ENVELOPED_DATA 654 +#define OID_PKCS7_SIGNED_ENVELOPED_DATA_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x04" +#define OID_PKCS7_DIGESTED_DATA_STR "1.2.840.113549.1.7.5" +#define OID_PKCS7_DIGESTED_DATA 655 +#define OID_PKCS7_DIGESTED_DATA_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x05" +#define OID_PKCS7_ENCRYPTED_DATA_STR "1.2.840.113549.1.7.6" +#define OID_PKCS7_ENCRYPTED_DATA 656 +#define OID_PKCS7_ENCRYPTED_DATA_HEX "\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x06" + +#define OID_OCSP_STR "1.3.6.1.5.5.7.48.1" +#define OID_OCSP 116 +#define OID_OCSP_HEX "\x06\x08\x2B\x06\x01\x05\x05\x07\x30\x01" +#define OID_BASIC_OCSP_RESPONSE_STR "1.3.6.1.5.5.7.48.1.1" +#define OID_BASIC_OCSP_RESPONSE 117 +#define OID_BASIC_OCSP_RESPONSE_HEX "\x06\x09\x2B\x06\x01\x05\x05\x07\x30\x01\x01" -#define PKCS12_BAG_TYPE_KEY 667 -#define PKCS12_BAG_TYPE_SHROUD 668 -#define PKCS12_BAG_TYPE_CERT 669 -#define PKCS12_BAG_TYPE_CRL 670 -#define PKCS12_BAG_TYPE_SECRET 671 -#define PKCS12_BAG_TYPE_SAFE 672 #define PBE12 1 #define PBES2 2 @@ -195,18 +345,6 @@ extern int32_t matrixCryptoGetPrngData(unsigned char *bytes, uint16_t size, #define PKCS12_IV_ID 2 #define PKCS12_MAC_ID 3 -#define PKCS9_CERT_TYPE_X509 675 -#define PKCS9_CERT_TYPE_SDSI 676 - -#define PKCS7_DATA 651 -/* signedData 1.2.840.113549.1.7.2 (2A 86 48 86 F7 0D 01 07 02) */ -#define PKCS7_SIGNED_DATA 652 -#define PKCS7_ENVELOPED_DATA 653 -#define PKCS7_SIGNED_ENVELOPED_DATA 654 -#define PKCS7_DIGESTED_DATA 655 -#define PKCS7_ENCRYPTED_DATA 656 -#endif /* USE_PKCS12 */ - #if defined(USE_PKCS1_OAEP) || defined(USE_PKCS1_PSS) #define PKCS1_SHA1_ID 0 #define PKCS1_MD5_ID 1 diff --git a/crypto/digest/digest.h b/crypto/digest/digest.h index 0bd9de5..4bd8166 100644 --- a/crypto/digest/digest.h +++ b/crypto/digest/digest.h @@ -48,6 +48,7 @@ #define SHA256_HASHLEN 32 #define SHA384_HASHLEN 48 #define SHA512_HASHLEN 64 +#define MD2_HASHLEN 16 #define MD5_HASHLEN 16 #define MD5SHA1_HASHLEN (MD5_HASHLEN + SHA1_HASHLEN) diff --git a/crypto/digest/hmac.c b/crypto/digest/hmac.c index b015587..cb31b94 100644 --- a/crypto/digest/hmac.c +++ b/crypto/digest/hmac.c @@ -137,8 +137,8 @@ void psHmacFinal(psHmac_t *ctx, unsigned char hash[MAX_HASHLEN]) If the keyLen is > 64 bytes, we hash the key and use it instead */ -#ifndef USE_MATRIX_MD5 -#error USE_MATRIX_MD5 required +#if !defined(USE_MATRIX_MD5) && !defined(USE_CL_DIGESTS) +#error USE_MATRIX_MD5 or USE_CL_DIGESTS required #endif int32_t psHmacMd5(const unsigned char *key, uint16_t keyLen, const unsigned char *buf, uint32_t len, diff --git a/crypto/keyformat/asn1.c b/crypto/keyformat/asn1.c index 81b04f7..069a0a8 100644 --- a/crypto/keyformat/asn1.c +++ b/crypto/keyformat/asn1.c @@ -350,6 +350,96 @@ int32_t getAsnAlgorithmIdentifier(const unsigned char **pp, uint32_t len, return rc; } +#ifndef MATRIXSSL_NO_OID_DATABASE +/* This function uses computed OID sums as base and adds suitable number of + multiples of OID_COLLISION in case the first known oid with the number + did not match. If function fails the value will be >= 32768. */ +static void checkAsnOidDatabase(int32_t *oi, + const unsigned char *oidStart, + uint32_t oidLen) +{ + /* The values are represented as C strings, although they contain + binary data. Therefore the type needs to be const char *. */ + const char *oid_hex; + /* Loop until match is found, adding multiples of OID_COLLISION in case of + mismatch. */ + while(1) { + switch(*oi) { + case OID_SHA1_ALG: oid_hex = OID_SHA1_ALG_HEX; break; + case OID_SHA256_ALG: oid_hex = OID_SHA256_ALG_HEX; break; + case OID_SHA384_ALG: oid_hex = OID_SHA384_ALG_HEX; break; + case OID_SHA512_ALG: oid_hex = OID_SHA512_ALG_HEX; break; + case OID_MD2_ALG: oid_hex = OID_MD2_ALG_HEX; break; + case OID_MD5_ALG: oid_hex = OID_MD5_ALG_HEX; break; + case OID_MD2_RSA_SIG: oid_hex = OID_MD2_RSA_SIG_HEX; break; + case OID_MD5_RSA_SIG: oid_hex = OID_MD5_RSA_SIG_HEX; break; + case OID_SHA1_RSA_SIG: oid_hex = OID_SHA1_RSA_SIG_HEX; break; + case OID_ID_MGF1: oid_hex = OID_ID_MGF1_HEX; break; + case OID_RSASSA_PSS: oid_hex = OID_RSASSA_PSS_HEX; break; + case OID_SHA256_RSA_SIG: oid_hex = OID_SHA256_RSA_SIG_HEX; break; + case OID_SHA384_RSA_SIG: oid_hex = OID_SHA384_RSA_SIG_HEX; break; + case OID_SHA512_RSA_SIG: oid_hex = OID_SHA512_RSA_SIG_HEX; break; + case OID_SHA1_DSA_SIG: oid_hex = OID_SHA1_DSA_SIG_HEX; break; + case OID_SHA1_ECDSA_SIG: oid_hex = OID_SHA1_ECDSA_SIG_HEX; break; + case OID_SHA224_ECDSA_SIG: oid_hex = OID_SHA224_ECDSA_SIG_HEX; break; + case OID_SHA256_ECDSA_SIG: oid_hex = OID_SHA256_ECDSA_SIG_HEX; break; + case OID_SHA384_ECDSA_SIG: oid_hex = OID_SHA384_ECDSA_SIG_HEX; break; + case OID_SHA512_ECDSA_SIG: oid_hex = OID_SHA512_ECDSA_SIG_HEX; break; + case OID_RSA_KEY_ALG: oid_hex = OID_RSA_KEY_ALG_HEX; break; + case OID_DSA_KEY_ALG: oid_hex = OID_DSA_KEY_ALG_HEX; break; + case OID_ECDSA_KEY_ALG: oid_hex = OID_ECDSA_KEY_ALG_HEX; break; + case OID_DES_EDE3_CBC: oid_hex = OID_DES_EDE3_CBC_HEX; break; + case OID_AES_128_CBC: oid_hex = OID_AES_128_CBC_HEX; break; + case OID_AES_128_WRAP: oid_hex = OID_AES_128_WRAP_HEX; break; + case OID_AES_128_GCM: oid_hex = OID_AES_128_GCM_HEX; break; + case OID_AES_192_CBC: oid_hex = OID_AES_192_CBC_HEX; break; + case OID_AES_192_WRAP: oid_hex = OID_AES_192_WRAP_HEX; break; + case OID_AES_192_GCM: oid_hex = OID_AES_192_GCM_HEX; break; + case OID_AES_256_CBC: oid_hex = OID_AES_256_CBC_HEX; break; + case OID_AES_256_WRAP: oid_hex = OID_AES_256_WRAP_HEX; break; + case OID_AES_256_GCM: oid_hex = OID_AES_256_GCM_HEX; break; + case OID_AES_CMAC: oid_hex = OID_AES_CMAC_HEX; break; + case OID_AES_CBC_CMAC_128: oid_hex = OID_AES_CBC_CMAC_128_HEX; break; + case OID_AES_CBC_CMAC_192: oid_hex = OID_AES_CBC_CMAC_192_HEX; break; + case OID_AES_CBC_CMAC_256: oid_hex = OID_AES_CBC_CMAC_256_HEX; break; + case OID_AUTH_ENC_256_SUM: oid_hex = OID_AUTH_ENC_256_SUM_HEX; break; + case OID_PKCS_PBKDF2: oid_hex = OID_PKCS_PBKDF2_HEX; break; + case OID_PKCS_PBES2: oid_hex = OID_PKCS_PBES2_HEX; break; + case OID_PKCS_PBESHA128RC4: oid_hex = OID_PKCS_PBESHA128RC4_HEX; break; + case OID_PKCS_PBESHA40RC4: oid_hex = OID_PKCS_PBESHA40RC4_HEX; break; + case OID_PKCS_PBESHA3DES3: oid_hex = OID_PKCS_PBESHA3DES3_HEX; break; + case OID_PKCS_PBESHA2DES3: oid_hex = OID_PKCS_PBESHA2DES3_HEX; break; + case OID_PKCS_PBESHA128RC2: oid_hex = OID_PKCS_PBESHA128RC2_HEX; break; + case OID_PKCS_PBESHA40RC2: oid_hex = OID_PKCS_PBESHA40RC2_HEX; break; + case OID_PKCS12_BAG_TYPE_KEY: oid_hex = OID_PKCS12_BAG_TYPE_KEY_HEX; break; + case OID_PKCS12_BAG_TYPE_SHROUD: oid_hex = OID_PKCS12_BAG_TYPE_SHROUD_HEX; break; + case OID_PKCS12_BAG_TYPE_CERT: oid_hex = OID_PKCS12_BAG_TYPE_CERT_HEX; break; + case OID_PKCS12_BAG_TYPE_CRL: oid_hex = OID_PKCS12_BAG_TYPE_CRL_HEX; break; + case OID_PKCS12_BAG_TYPE_SECRET: oid_hex = OID_PKCS12_BAG_TYPE_SECRET_HEX; break; + case OID_PKCS12_BAG_TYPE_SAFE: oid_hex = OID_PKCS12_BAG_TYPE_SAFE_HEX; break; + case OID_PKCS9_CERT_TYPE_X509: oid_hex = OID_PKCS9_CERT_TYPE_X509_HEX; break; + case OID_PKCS9_CERT_TYPE_SDSI: oid_hex = OID_PKCS9_CERT_TYPE_SDSI_HEX; break; + case OID_PKCS7_DATA: oid_hex = OID_PKCS7_DATA_HEX; break; + case OID_PKCS7_SIGNED_DATA: oid_hex = OID_PKCS7_SIGNED_DATA_HEX; break; + case OID_PKCS7_ENVELOPED_DATA: oid_hex = OID_PKCS7_ENVELOPED_DATA_HEX; break; + case OID_PKCS7_SIGNED_ENVELOPED_DATA: oid_hex = OID_PKCS7_SIGNED_ENVELOPED_DATA_HEX; break; + case OID_PKCS7_DIGESTED_DATA: oid_hex = OID_PKCS7_DIGESTED_DATA_HEX; break; + case OID_PKCS7_ENCRYPTED_DATA: oid_hex = OID_PKCS7_ENCRYPTED_DATA_HEX; break; + case OID_OCSP: oid_hex = OID_OCSP_HEX; break; + case OID_BASIC_OCSP_RESPONSE: oid_hex = OID_BASIC_OCSP_RESPONSE_HEX; break; + default: + /* No possible matches: bitwise-add not found constant to OID. */ + *oi |= OID_NOT_FOUND; + return; + } + /* Ignore tag, but use length byte and data from binary oid. */ + if (oidLen == oid_hex[1] && !memcmp(oidStart, &oid_hex[2], oidLen)) + return; + *oi += OID_COLLISION; + } +} +#endif /* MATRIXSSL_NO_OID_DATABASE */ + /******************************************************************************/ int32_t getAsnOID(const unsigned char **pp, uint32_t len, int32_t *oi, @@ -358,6 +448,8 @@ int32_t getAsnOID(const unsigned char **pp, uint32_t len, int32_t *oi, const unsigned char *p = *pp, *end; int32_t plen, rc; uint32_t arcLen; + const unsigned char *oidStart; + uint32_t oidLen; rc = PS_PARSE_FAIL; end = p + len; @@ -375,12 +467,18 @@ int32_t getAsnOID(const unsigned char **pp, uint32_t len, int32_t *oi, return PS_LIMIT_FAIL; } *oi = 0; + oidStart = p; + oidLen = arcLen; while (arcLen > 0) { *oi += *p; p++; arcLen--; } +#ifndef MATRIXSSL_NO_OID_DATABASE + checkAsnOidDatabase(oi, oidStart, oidLen); +#endif /* MATRIXSSL_NO_OID_DATABASE */ + if (checkForParams) { plen -= (end - p); *paramLen = len - plen; diff --git a/crypto/keyformat/crl.c b/crypto/keyformat/crl.c index f6bb9b6..3bc533f 100644 --- a/crypto/keyformat/crl.c +++ b/crypto/keyformat/crl.c @@ -331,84 +331,36 @@ static int32 internalMatchSubject(psX509Cert_t *cert, psX509Crl_t *CRL) return 1; } -/* -1 is exired */ -static int32_t nextUpdateTest(char *c, int32 timeType) +/* Check if nextUpdate time appears correct. Returns -1 when + timestamp was unparseable or the CRL was expired. 0 for success. */ +static int32_t nextUpdateTest(const char *c, int32 timeType) { - unsigned int y; - unsigned short m,d,h; -#ifdef POSIX - struct tm t; - time_t rawtime; -#endif -#ifdef WIN32 - SYSTEMTIME sysTime; -#endif - - /* UTCTIME, defined in 1982, has just a 2 digit year */ - /* year as unsigned int handles over/underflows */ - if (timeType == ASN_UTCTIME) { - y = 2000 + 10 * (c[0] - '0') + (c[1] - '0'); c += 2; - /* Years from '96 through '99 are in the 1900's */ - if (y >= 2096) { - y -= 100; - } - } - else { - y = 1000 * (c[0] - '0') + 100 * (c[1] - '0') + - 10 * (c[2] - '0') + (c[3] - '0'); c += 4; - } - /* month,day as unsigned short handles over/underflows */ - m = 10 * (c[0] - '0') + (c[1] - '0'); c += 2; - d = 10 * (c[0] - '0') + (c[1] - '0'); c += 2; - h = 10 * (c[0] - '0') + (c[1] - '0'); c += 2; + int32 err; + psBrokenDownTime_t timeNow; + psBrokenDownTime_t nextTime; + psBrokenDownTime_t nextTimeLinger; -#ifdef POSIX - time(&rawtime); - localtime_r(&rawtime, &t); - /* Localtime does months from 0-11 and (year-1900)! Normalize it. */ - t.tm_mon++; - t.tm_year += 1900; - - if (t.tm_year > (int)y) { + err = psGetBrokenDownGMTime(&timeNow, 0); + if (err != PS_SUCCESS) return -1; - } else if (t.tm_year == (int)y) { - if (t.tm_mon > m) { - return -1; - } else if (t.tm_mon == m) { - if (t.tm_mday > d) { - return -1; - } else if (t.tm_mday == d) { - if (t.tm_hour > h) { - return -1; - } - } - } - } -#endif -#ifdef WIN32 - GetSystemTime(&sysTime); + err = psBrokenDownTimeImport( + &nextTime, c, strlen(c), + timeType == ASN_UTCTIME ? + PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR : 0); + if (err != PS_SUCCESS) + return -1; - if (sysTime.wYear > (int)y) { + memcpy(&nextTimeLinger, &nextTime, sizeof nextTimeLinger); + err = psBrokenDownTimeAdd(&nextTimeLinger, PS_CRL_TIME_LINGER); + if (err != PS_SUCCESS) + return -1; + + if (psBrokenDownTimeCmp(&timeNow, &nextTimeLinger) > 0) { + /* nextTime is in past. */ return -1; } - else if (sysTime.wYear == (int)y) { - if (sysTime.wMonth > m) { - return -1; - } else if (sysTime.wMonth == m) { - if (sysTime.wDay > d) { - return -1; - } else if (sysTime.wDay == d) { - if (sysTime.wHour > h) { - return -1; - } - } - } - } -#endif - return 0; - } static psX509Crl_t* internalGetCrlForCert(psX509Cert_t *cert) diff --git a/crypto/keyformat/pkcs.c b/crypto/keyformat/pkcs.c index e53be48..5d44a7a 100644 --- a/crypto/keyformat/pkcs.c +++ b/crypto/keyformat/pkcs.c @@ -446,7 +446,7 @@ static int32 psParseIntegrityMode(const unsigned char **buf, int32 totLen) return rc; } - if (oi == PKCS7_DATA) { + if (oi == OID_PKCS7_DATA) { /* Data ::= OCTET STRING */ if (*p++ != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { return PS_PARSE_FAIL; @@ -460,7 +460,7 @@ static int32 psParseIntegrityMode(const unsigned char **buf, int32 totLen) return PS_FAILURE; } rc = PASSWORD_INTEGRITY; - } else if (oi == PKCS7_SIGNED_DATA) { + } else if (oi == OID_PKCS7_SIGNED_DATA) { psTraceCrypto("SignedData integrity mode not supported\n"); return PS_UNSUPPORTED_FAIL; /* rc = PUBKEY_INTEGRITY; */ @@ -913,7 +913,7 @@ static int32 parseSafeContents(psPool_t *pool, unsigned char *password, } switch (bagoi) { - case PKCS12_BAG_TYPE_CERT: + case OID_PKCS12_BAG_TYPE_CERT: /* CertBag ::= SEQUENCE { certId BAG-TYPE.&id ({CertTypes}), @@ -937,7 +937,7 @@ static int32 parseSafeContents(psPool_t *pool, unsigned char *password, psTraceCrypto("Initial CertBag parse failure\n"); return rc; } - if (certoi != PKCS9_CERT_TYPE_X509) { + if (certoi != OID_PKCS9_CERT_TYPE_X509) { psTraceIntCrypto("Unsupported CertBag type %d\n", certoi); return PS_UNSUPPORTED_FAIL; } @@ -975,7 +975,7 @@ static int32 parseSafeContents(psPool_t *pool, unsigned char *password, p += rc; break; - case PKCS12_BAG_TYPE_SHROUD: + case OID_PKCS12_BAG_TYPE_SHROUD: /* A PKCS8ShroudedKeyBag holds a private key, which has been shrouded in accordance with PKCS #8. Note that a PKCS8ShroudedKeyBag holds only one shrouded private key. */ @@ -999,7 +999,7 @@ static int32 parseSafeContents(psPool_t *pool, unsigned char *password, psFree(pt, pool); p += cryptlen; break; - case PKCS12_BAG_TYPE_KEY: + case OID_PKCS12_BAG_TYPE_KEY: if ((rc = pkcs8ParsePrivBin(pool, (unsigned char*)p, tmplen, NULL, privKey)) < 0) { psTraceIntCrypto("Failed PKCS8 key parse %d\n", rc); @@ -1072,7 +1072,7 @@ static int32 psParseAuthenticatedSafe(psPool_t *pool, psX509Cert_t **cert, psTraceCrypto("Initial content info parse failure\n"); return rc; } - if (oi == PKCS7_ENCRYPTED_DATA) { + if (oi == OID_PKCS7_ENCRYPTED_DATA) { /* password protected mode */ if (*p++ != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { psTraceCrypto("Initial pkcs7 encrypted data parse failure\n"); @@ -1110,7 +1110,7 @@ static int32 psParseAuthenticatedSafe(psPool_t *pool, psX509Cert_t **cert, psTraceCrypto("Initial EncryptedContentInfo parse failure\n"); return rc; } - psAssert(oi == PKCS7_DATA); + psAssert(oi == OID_PKCS7_DATA); if ((rc = pkcs12import(pool, &p, (int32)(end - p), importPass, ipassLen, &pt, &tmplen)) < 0) { @@ -1129,7 +1129,7 @@ static int32 psParseAuthenticatedSafe(psPool_t *pool, psX509Cert_t **cert, } psFree(pt, pool); p += rc; - } else if (oi == PKCS7_DATA) { + } else if (oi == OID_PKCS7_DATA) { /* Data ::= OCTET STRING */ if (*p++ != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)) { psTraceCrypto("Initial pkcs7 data parse failure\n"); @@ -1337,7 +1337,7 @@ ERR_FBUF: #ifdef MATRIX_USE_FILE_SYSTEM -#ifdef USE_PKCS5 +#if defined(USE_PKCS5) && defined(USE_PBKDF1) /******************************************************************************/ /* Convert an ASCII hex representation to a binary buffer. @@ -1372,7 +1372,7 @@ static int32 hexToBinary(unsigned char *hex, unsigned char *bin, int32 binlen) } return binlen * 2; } -#endif /* USE_PKCS5 */ +#endif /* USE_PKCS5 && USE_PBKDF1 */ #ifdef USE_RSA int32_t pkcs1ParsePubFile(psPool_t *pool, const char *fileName, psRsaKey_t *key) @@ -1475,7 +1475,7 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, char *start, *end, *endTmp; int32 keyBufLen, rc; uint32 PEMlen = 0; -#ifdef USE_PKCS5 +#if defined(USE_PKCS5) && defined(USE_PBKDF1) psDes3_t dctx; psAesCbc_t actx; unsigned char passKey[32]; /* AES-256 max */ @@ -1484,7 +1484,7 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, static const char des3encryptHeader[] = "DEK-Info: DES-EDE3-CBC,"; static const char aes128encryptHeader[] = "DEK-Info: AES-128-CBC,"; -#endif /* USE_PKCS5 */ +#endif /* USE_PKCS5 && USE_PBKDF1 */ if (fileName == NULL) { psTraceCrypto("No fileName passed to pkcs1DecodePrivFile\n"); @@ -1522,7 +1522,7 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, if (strstr((char*)keyBuf, "Proc-Type:") && strstr((char*)keyBuf, "4,ENCRYPTED")) { -#ifdef USE_PKCS5 +#if defined(USE_PKCS5) && defined(USE_PBKDF1) if (password == NULL) { psTraceCrypto("No password given for encrypted private key file\n"); psFree(keyBuf, pool); @@ -1551,15 +1551,24 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, return PS_FAILURE; } start += tmp; - pkcs5pbkdf1((unsigned char*)password, strlen(password), - cipherIV, 1, (unsigned char*)passKey); + if (pkcs5pbkdf1((unsigned char*)password, strlen(password), + cipherIV, 1, (unsigned char*)passKey) < 0) { + psTraceCrypto("pkcs5pbkdf1 failed\n"); + psFree(keyBuf, pool); + return PS_FAILURE; + } PEMlen = (int32)(end - start); -#else /* !USE_PKCS5 */ +#else /* !USE_PKCS5 || !USE_PBKDF1 */ /* The private key is encrypted, but PKCS5 support has been turned off */ +#ifndef USE_PKCS5 psTraceCrypto("USE_PKCS5 must be enabled for key file password\n"); +#endif /* USE_PKCS5 */ +#ifndef USE_PBKDF1 + psTraceCrypto("USE_PBKDF1 must be enabled for key file password\n"); +#endif /* USE_PBKDF1 */ psFree(keyBuf, pool); return PS_UNSUPPORTED_FAIL; -#endif /* USE_PKCS5 */ +#endif /* USE_PKCS5 && USE_PBKDF1 */ } /* Take the raw input and do a base64 decode */ @@ -1582,7 +1591,7 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, } psFree(keyBuf, pool); -#ifdef USE_PKCS5 +#if defined(USE_PKCS5) && defined(USE_PBKDF1) if (encrypted == 1 && password) { psDes3Init(&dctx, cipherIV, passKey); psDes3Decrypt(&dctx, dout, dout, *DERlen); @@ -1596,7 +1605,7 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, } /* SECURITY - zero out keys when finished */ memset_s(passKey, sizeof(passKey), 0x0, sizeof(passKey)); -#endif /* USE_PKCS5 */ +#endif /* USE_PKCS5 && USE_PBKDF1 */ *DERout = dout; return PS_SUCCESS; @@ -1608,6 +1617,7 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, /******************************************************************************/ #ifdef USE_PKCS5 +#ifdef USE_PBKDF1 /******************************************************************************/ /* Generate a key given a password and salt value. @@ -1629,21 +1639,30 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, salt is assumed to point to 8 bytes of data key is assumed to point to 24 bytes of data */ -void pkcs5pbkdf1(unsigned char *pass, uint32 passlen, unsigned char *salt, - int32 iter, unsigned char *key) +int32_t pkcs5pbkdf1(unsigned char *pass, uint32 passlen, unsigned char *salt, + int32 iter, unsigned char *key) { + int32_t rc; psDigestContext_t md; unsigned char md5[MD5_HASH_SIZE]; - psAssert(iter == 1); - psMd5Init(&md.md5); + rc = psMd5Init(&md.md5); + if (rc != PS_SUCCESS) { + psTraceCrypto("psMd5Init failed. Please ensure non-FIPS mode.\n"); + return rc; + } psMd5Update(&md.md5, pass, passlen); psMd5Update(&md.md5, salt, 8); psMd5Final(&md.md5, md5); memcpy(key, md5, MD5_HASH_SIZE); - psMd5Init(&md.md5); + rc = psMd5Init(&md.md5); + if (rc != PS_SUCCESS) { + psTraceCrypto("psMd5Init failed. Please ensure non-FIPS mode.\n"); + return rc; + } + psMd5Update(&md.md5, md5, MD5_HASH_SIZE); psMd5Update(&md.md5, pass, passlen); psMd5Update(&md.md5, salt, 8); @@ -1652,7 +1671,9 @@ void pkcs5pbkdf1(unsigned char *pass, uint32 passlen, unsigned char *salt, memset_s(md5, MD5_HASH_SIZE, 0x0, MD5_HASH_SIZE); memset_s(&md, sizeof(psDigestContext_t), 0x0, sizeof(psDigestContext_t)); + return PS_SUCCESS; } +#endif /* USE_PBKDF1 */ #if defined(USE_HMAC_SHA1) /******************************************************************************/ @@ -1872,11 +1893,13 @@ static int32 pkcs_1_mgf1(psPool_t *pool, const unsigned char *seed, psSha1Update(&md.sha1, seed, seedlen); psSha1Update(&md.sha1, buf, 4); psSha1Final(&md.sha1, buf); +#ifdef USE_MD5 } else if (hash_idx == PKCS1_MD5_ID) { psMd5Init(&md.md5); psMd5Update(&md.md5, seed, seedlen); psMd5Update(&md.md5, buf, 4); psMd5Final(&md.md5, buf); +#endif /* USE_MD5 */ #ifdef USE_SHA256 } else if (hash_idx == PKCS1_SHA256_ID) { psSha256Init(&md.sha256); @@ -1951,7 +1974,13 @@ int32 pkcs1OaepEncode(psPool_t *pool, const unsigned char *msg, uint32 msglen, if (hash_idx == PKCS1_SHA1_ID) { hLen = SHA1_HASH_SIZE; } else if (hash_idx == PKCS1_MD5_ID) { +#ifdef USE_MD5 hLen = MD5_HASH_SIZE; +#else + psTraceCrypto("MD5 not supported in this build."); + psTraceCrypto(" Please enable USE_MD5\n"); + return PS_UNSUPPORTED_FAIL; +#endif /* USE_MD5 */ } else { psTraceStrCrypto("Bad hash index to OAEP encode\n", NULL); return PS_ARG_FAIL; @@ -2003,22 +2032,28 @@ int32 pkcs1OaepEncode(psPool_t *pool, const unsigned char *msg, uint32 msglen, psSha1Init(&md.sha1); psSha1Update(&md.sha1, lparam, lparamlen); psSha1Final(&md.sha1, DB); - } else { + } +#ifdef USE_MD5 + else { psMd5Init(&md.md5); psMd5Update(&md.md5, lparam, lparamlen); psMd5Final(&md.md5, DB); } +#endif /* USE_MD5 */ } else { /* can't pass hash a NULL so use DB with zero length */ if (hash_idx == PKCS1_SHA1_ID) { psSha1Init(&md.sha1); psSha1Update(&md.sha1, DB, 0); psSha1Final(&md.sha1, DB); - } else { + } +#ifdef USE_MD5 + else { psMd5Init(&md.md5); psMd5Update(&md.md5, DB, 0); psMd5Final(&md.md5, DB); } +#endif /* USE_MD5 */ } /* @@ -2155,7 +2190,13 @@ int32 pkcs1OaepDecode(psPool_t *pool, const unsigned char *msg, uint32 msglen, if (hash_idx == PKCS1_SHA1_ID) { hLen = SHA1_HASH_SIZE; } else if (hash_idx == PKCS1_MD5_ID) { +#ifdef USE_MD5 hLen = MD5_HASH_SIZE; +#else + psTraceCrypto("MD5 not supported in this build."); + psTraceCrypto(" Please enable USE_MD5\n"); + return PS_UNSUPPORTED_FAIL; +#endif /* USE_MD5 */ } else { psTraceStrCrypto("Bad hash index to OAEP decode\n", NULL); return PS_ARG_FAIL; @@ -2261,22 +2302,28 @@ int32 pkcs1OaepDecode(psPool_t *pool, const unsigned char *msg, uint32 msglen, psSha1Init(&md.sha1); psSha1Update(&md.sha1, lparam, lparamlen); psSha1Final(&md.sha1, seed); - } else { + } +#ifdef USE_MD5 + else { psMd5Init(&md.md5); psMd5Update(&md.md5, lparam, lparamlen); psMd5Final(&md.md5, seed); } +#endif /* USE_MD5 */ } else { /* can't pass hash routine a NULL so use DB with zero length */ if (hash_idx == PKCS1_SHA1_ID) { psSha1Init(&md.sha1); psSha1Update(&md.sha1, DB, 0); psSha1Final(&md.sha1, seed); - } else { + } +#ifdef USE_MD5 + else { psMd5Init(&md.md5); psMd5Update(&md.md5, DB, 0); psMd5Final(&md.md5, seed); } +#endif /* USE_MD5 */ } /* @@ -2363,7 +2410,13 @@ int32 pkcs1PssEncode(psPool_t *pool, const unsigned char *msghash, if (hash_idx == PKCS1_SHA1_ID) { hLen = SHA1_HASH_SIZE; } else if (hash_idx == PKCS1_MD5_ID) { +#ifdef USE_MD5 hLen = MD5_HASH_SIZE; +#else + psTraceCrypto("MD5 not supported in this build."); + psTraceCrypto(" Please enable USE_MD5\n"); + return PS_UNSUPPORTED_FAIL; +#endif /* USE_MD5 */ #ifdef USE_SHA256 } else if (hash_idx == PKCS1_SHA256_ID) { hLen = SHA256_HASH_SIZE; @@ -2419,13 +2472,16 @@ int32 pkcs1PssEncode(psPool_t *pool, const unsigned char *msghash, psSha1Update(&md.sha1, msghash, msghashlen); psSha1Update(&md.sha1, salt, saltlen); psSha1Final(&md.sha1, hash); - } else if (hash_idx == PKCS1_MD5_ID) { + } +#ifdef USE_MD5 + if (hash_idx == PKCS1_MD5_ID) { psMd5Init(&md.md5); psMd5Update(&md.md5, DB, 8); /* 8 0's */ psMd5Update(&md.md5, msghash, msghashlen); psMd5Update(&md.md5, salt, saltlen); psMd5Final(&md.md5, hash); } +#endif /* USE_MD5 */ #ifdef USE_SHA256 if (hash_idx == PKCS1_SHA256_ID) { psSha256Init(&md.sha256); @@ -2523,7 +2579,13 @@ int32 pkcs1PssDecode(psPool_t *pool, const unsigned char *msghash, if (hash_idx == PKCS1_SHA1_ID) { hLen = SHA1_HASH_SIZE; } else if (hash_idx == PKCS1_MD5_ID) { +#ifdef USE_MD5 hLen = MD5_HASH_SIZE; +#else + psTraceCrypto("MD5 not supported in this build."); + psTraceCrypto(" Please enable USE_MD5\n"); + return PS_UNSUPPORTED_FAIL; +#endif /* USE_MD5 */ #ifdef USE_SHA256 } else if (hash_idx == PKCS1_SHA256_ID) { hLen = SHA256_HASH_SIZE; @@ -2629,7 +2691,9 @@ int32 pkcs1PssDecode(psPool_t *pool, const unsigned char *msghash, psSha1Update(&md.sha1, msghash, msghashlen); psSha1Update(&md.sha1, DB+x, saltlen); psSha1Final(&md.sha1, mask); - } else if (hash_idx == PKCS1_MD5_ID) { + } +#ifdef USE_MD5 + if (hash_idx == PKCS1_MD5_ID) { psMd5Init(&md.md5); memset(mask, 0x0, 8); psMd5Update(&md.md5, mask, 8); @@ -2637,6 +2701,8 @@ int32 pkcs1PssDecode(psPool_t *pool, const unsigned char *msghash, psMd5Update(&md.md5, DB+x, saltlen); psMd5Final(&md.md5, mask); } +#endif /* USE_MD5 */ + #ifdef USE_SHA256 if (hash_idx == PKCS1_SHA256_ID) { psSha256Init(&md.sha256); diff --git a/crypto/keyformat/x509.c b/crypto/keyformat/x509.c index b457518..33559b5 100644 --- a/crypto/keyformat/x509.c +++ b/crypto/keyformat/x509.c @@ -46,6 +46,10 @@ #define MAX_CERTS_PER_FILE 16 +/* Maximum time length accepted. + Allows RFC 5280 format time + nanosecond fractional time + non-Zulu time. */ +#define MAX_TIME_LEN 32 + #ifdef USE_CERT_PARSE /* Certificate extensions @@ -500,7 +504,7 @@ static int32 getRsaPssParams(const unsigned char **pp, int32 size, *pp = (unsigned char*)p; return PS_SUCCESS; } -#endif +#endif /* USE_PKCS1_PSS */ /******************************************************************************/ /* @@ -554,15 +558,17 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, psX509Cert_t **outcert, int32 flags) { psX509Cert_t *cert; - const unsigned char *p, *end, *far_end, *certStart, *tbsCertStart; + const unsigned char *p, *end, *far_end, *certStart; uint16_t len; uint32_t oneCertLen; - int32 parsing, rc; - unsigned char sha1KeyHash[SHA1_HASH_SIZE]; -#ifdef USE_CERT_PARSE - psDigestContext_t hashCtx; + int32_t parsing, rc; const unsigned char *certEnd; - uint16_t certLen, plen; + uint16_t plen; +#ifdef USE_CERT_PARSE + const unsigned char *tbsCertStart; + unsigned char sha1KeyHash[SHA1_HASH_SIZE]; + psDigestContext_t hashCtx; + uint16_t certLen; const unsigned char *p_subject_pubkey_info; size_t subject_pubkey_info_header_len; #endif /* USE_CERT_PARSE */ @@ -579,6 +585,9 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, } memset(cert, 0x0, sizeof(psX509Cert_t)); cert->pool = pool; +#ifdef USE_CERT_PARSE + cert->extensions.bc.cA = CA_UNDEFINED; +#endif /* USE_CERT_PARSE */ p = pp; far_end = p + size; @@ -629,6 +638,7 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, #ifdef USE_CERT_PARSE tbsCertStart = p; +#endif /* USE_CERT_PARSE */ /* TBSCertificate ::= SEQUENCE { version [0] EXPLICIT Version DEFAULT v1, @@ -650,8 +660,11 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, return rc; } certEnd = p + len; +#ifdef USE_CERT_PARSE +/* + Start parsing TBSCertificate contents. +*/ certLen = certEnd - tbsCertStart; - /* Version ::= INTEGER { v1(0), v2(1), v3(2) } */ @@ -883,12 +896,17 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, psTraceCrypto("Error. Cert has no name information\n"); return PS_PARSE_FAIL; } +#else /* No TBSCertificate parsing. */ + p = certEnd; +#endif /* USE_CERT_PARSE (end of TBSCertificate parsing) */ + /* Certificate signature info */ if ((rc = getAsnAlgorithmIdentifier(&p, (uint32)(end - p), &cert->sigAlgorithm, &plen)) < 0) { psTraceCrypto("Couldn't get algorithm identifier for sigAlgorithm\n"); return rc; } + if (plen != 0) { #ifdef USE_PKCS1_PSS if (cert->sigAlgorithm == OID_RSASSA_PSS) { @@ -916,8 +934,9 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, #else psTraceCrypto("Unsupported X.509 sigAlgorithm\n"); return PS_UNSUPPORTED_FAIL; -#endif +#endif /* USE_PKCS1_PSS */ } +#ifdef USE_CERT_PARSE /* Signature algorithm must match that specified in TBS cert */ @@ -937,7 +956,7 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, psMd2Update(&hashCtx.md2, tbsCertStart, certLen); psMd2Final(&hashCtx.md2, cert->sigHash); break; -#endif +#endif /* USE_MD2 */ case OID_MD5_RSA_SIG: psMd5Init(&hashCtx.md5); psMd5Update(&hashCtx.md5, tbsCertStart, certLen); @@ -1049,6 +1068,7 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, cert->certAlgorithm); return PS_UNSUPPORTED_FAIL; } +#endif /* USE_CERT_PARSE */ if ((rc = psX509GetSignature(pool, &p, (uint32)(end - p), &cert->signature, &cert->signatureLen)) < 0) { @@ -1056,9 +1076,11 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, return rc; } -#else /* !USE_CERT_PARSE */ - p = certStart + len + (int32)(p - certStart); -#endif /* USE_CERT_PARSE */ +#ifndef USE_CERT_PARSE + /* Some APIs need certAlgorithm.*/ + cert->certAlgorithm = cert->sigAlgorithm; +#endif /* !USE_CERT_PARSE */ + /* The ability to parse additional chained certs is a PKI product feature addition. Chaining in MatrixSSL is handled internally. @@ -1066,7 +1088,7 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, if ((p != far_end) && (p < (far_end + 1))) { if (*p == 0x0 && *(p + 1) == 0x0) { parsing = 0; /* An indefinite length stream was passed in */ - /* caller will have to deal with skipping these becuase they + /* caller will have to deal with skipping these because they would have read off the TL of this ASN.1 stream */ } else { cert->next = psMalloc(pool, sizeof(psX509Cert_t)); @@ -1086,6 +1108,7 @@ int32 psX509ParseCert(psPool_t *pool, const unsigned char *pp, uint32 size, return (int32)(p - pp); } +#ifdef USE_CERT_PARSE static void freeOrgUnitList(x509OrgUnit_t *orgUnit, psPool_t *allocPool) { x509OrgUnit_t *ou; @@ -1109,7 +1132,6 @@ static void freeDomainComponentList(x509DomainComponent_t *domainComponent, } } -#ifdef USE_CERT_PARSE void x509FreeExtensions(x509v3extensions_t *extensions) { @@ -1404,7 +1426,6 @@ void psX509FreeCert(psX509Cert_t *cert) } } -#ifdef USE_CERT_PARSE /******************************************************************************/ /* Currently just returning the raw BIT STRING and size in bytes @@ -1440,6 +1461,7 @@ int32_t psX509GetSignature(psPool_t *pool, const unsigned char **pp, uint16_t le return PS_SUCCESS; } +#ifdef USE_CERT_PARSE /******************************************************************************/ /* Validate the expected name against a subset of the GeneralName rules @@ -1527,7 +1549,7 @@ static int32_t parseGeneralNames(psPool_t *pool, const unsigned char **buf, } p = *buf; end = p + len; - + while (len > 0) { if (firstName == NULL) { activeName = firstName = psMalloc(pool, sizeof(x509GeneralName_t)); @@ -1652,6 +1674,10 @@ static int32_t parseGeneralNames(psPool_t *pool, const unsigned char **buf, return PS_PARSE_FAIL; } len -= (p - save); + if (len < activeName->dataLen) { + psTraceCrypto("ASN len error in parseGeneralNames\n"); + return PS_PARSE_FAIL; + } /* Currently we validate that the IA5String fields are printable At a minimum, this prevents attacks with null terminators or @@ -2588,7 +2614,7 @@ KNOWN_EXT: extensions->bc.cA = CA_FALSE; p++; } else { - extensions->bc.cA = CA_UNDEFINED; + extensions->bc.cA = CA_FALSE; } /* Now need to check if there is a path constraint. Only makes @@ -3182,25 +3208,6 @@ static int32_t getExplicitVersion(const unsigned char **pp, uint16_t len, return PS_SUCCESS; } -/******************************************************************************/ -/** - Verify a string has nearly valid date range format and length. - */ -static unsigned char asciidate(const unsigned char *c, unsigned int utctime) -{ - if (utctime != ASN_UTCTIME) { /* 4 character year */ - if (*c < '1' && *c > '2') return 0; c++; /* Year 1900 - 2999 */ - if (*c < '0' && *c > '9') return 0; c++; - } - if (*c < '0' && *c > '9') return 0; c++; - if (*c < '0' && *c > '9') return 0; c++; - if (*c < '0' && *c > '1') return 0; c++; /* Month 00 - 19 */ - if (*c < '0' && *c > '9') return 0; c++; - if (*c < '0' && *c > '3') return 0; c++; /* Day 00 - 39 */ - if (*c < '0' && *c > '9') return 0; - return 1; -} - /******************************************************************************/ /** Tests if the certificate was issued before the given date. @@ -3220,31 +3227,25 @@ static int32 issuedBefore(rfc_e rfc, const psX509Cert_t *cert) unsigned char *c; unsigned int y; unsigned short m; + psBrokenDownTime_t t; + int32 err; /* Validate the 'not before' date */ if ((c = (unsigned char *)cert->notBefore) == NULL) { return PS_FAILURE; } - /* UTCTIME, defined in 1982, has just a 2 digit year */ - /* year as unsigned int handles over/underflows */ - if (cert->notBeforeTimeType == ASN_UTCTIME) { - if (!asciidate(c, ASN_UTCTIME)) { - return PS_FAILURE; - } - y = 2000 + 10 * (c[0] - '0') + (c[1] - '0'); c += 2; - /* Years from '96 through '99 are in the 1900's */ - if (y >= 2096) { - y -= 100; - } - } else { - if (!asciidate(c, 0)) { - return PS_FAILURE; - } - y = 1000 * (c[0] - '0') + 100 * (c[1] - '0') + - 10 * (c[2] - '0') + (c[3] - '0'); c += 4; - } - /* month as unsigned short handles over/underflows */ - m = 10 * (c[0] - '0') + (c[1] - '0'); + err = psBrokenDownTimeImport( + &t, (const char *) c, strlen((const char *)c), + cert->notBeforeTimeType == ASN_UTCTIME ? + PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR : 0); + + if (err) + return err; + + /* Get y and m from broken-down time. */ + y = 1900 + (unsigned int) t.tm_year; + m = 1 + (unsigned short) t.tm_mon; + /* Must have been issued at least when X509v3 was added */ if (y < 1996 || m < 1 || m > 12) { return -1; @@ -3276,59 +3277,6 @@ static int32 issuedBefore(rfc_e rfc, const psX509Cert_t *cert) return -1; } -/******************************************************************************/ -/** - Pulls the year, month and day out of the certificate notBefore and - notAfter dates. -*/ -static int32 getDateComponents(psX509Cert_t *cert, int beforeOrAfter, - unsigned int *y, unsigned short *m, unsigned short *d) -{ - unsigned char *c; - int32 timeType; - - if (beforeOrAfter == 0) { - /* Parse the 'not before' date */ - if ((c = (unsigned char *)cert->notBefore) == NULL) { - return PS_FAILURE; - } - timeType = cert->notBeforeTimeType; - } else { - /* Parse the 'not after' date */ - if ((c = (unsigned char *)cert->notAfter) == NULL) { - return PS_FAILURE; - } - timeType = cert->notAfterTimeType; - } - /* UTCTIME, defined in 1982, has just a 2 digit year */ - /* year as unsigned int handles over/underflows */ - if (timeType == ASN_UTCTIME) { - if (!asciidate(c, ASN_UTCTIME)) { - return PS_FAILURE; - } - *y = 2000 + 10 * (c[0] - '0') + (c[1] - '0'); c += 2; - /* Years from '96 through '99 are in the 1900's */ - if (*y >= 2096) { - *y -= 100; - } - } - else { - if (!asciidate(c, 0)) { - return PS_FAILURE; - } - *y = 1000 * (c[0] - '0') + 100 * (c[1] - '0') + - 10 * (c[2] - '0') + (c[3] - '0'); c += 4; - } - /* month,day as unsigned short handles over/underflows */ - *m = 10 * (c[0] - '0') + (c[1] - '0'); c += 2; - *d = 10 * (c[0] - '0') + (c[1] - '0'); - /* Must have been issued at least when X509v3 was added */ - if (*y < 1996 || *m < 1 || *m > 12 || *d < 1 || *d > 31) { - return PS_FAILURE; - } - return PS_SUCCESS; -} - /** Validate the dates in the cert to machine date. SECURITY - always succeeds on systems without date support @@ -3338,96 +3286,58 @@ static int32 getDateComponents(psX509Cert_t *cert, int beforeOrAfter, */ static int32 validateDateRange(psX509Cert_t *cert) { - unsigned int y; - unsigned short m, d; + int32 err; + psBrokenDownTime_t timeNow; + psBrokenDownTime_t timeNowLinger; + psBrokenDownTime_t beforeTime; + psBrokenDownTime_t afterTime; + psBrokenDownTime_t afterTimeLinger; -#ifdef POSIX - struct tm t; - time_t rawtime; + if (cert->notBefore == NULL || cert->notAfter == NULL) + return PS_FAIL; + err = psGetBrokenDownGMTime(&timeNow, 0); + if (err != PS_SUCCESS) + return PS_FAIL; - time(&rawtime); - localtime_r(&rawtime, &t); - /* Localtime does months from 0-11 and (year-1900)! Normalize it. */ - t.tm_mon++; - t.tm_year += 1900; + memcpy(&timeNowLinger, &timeNow, sizeof timeNowLinger); + err = psBrokenDownTimeAdd(&timeNowLinger, PS_X509_TIME_LINGER); + if (err != PS_SUCCESS) + return PS_FAIL; - if (getDateComponents(cert, 0, &y, &m, &d) < 0) { - return PS_FAILURE; - } - - if (t.tm_year < (int)y) { + err = psBrokenDownTimeImport( + &beforeTime, cert->notBefore, strlen(cert->notBefore), + cert->notBeforeTimeType == ASN_UTCTIME ? + PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR : 0); + if (err != PS_SUCCESS) + return PS_FAIL; + + err = psBrokenDownTimeImport( + &afterTime, cert->notAfter, strlen(cert->notAfter), + cert->notAfterTimeType == ASN_UTCTIME ? + PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR : 0); + if (err != PS_SUCCESS) + return PS_FAIL; + + memcpy(&afterTimeLinger, &afterTime, sizeof afterTimeLinger); + err = psBrokenDownTimeAdd(&afterTimeLinger, PS_X509_TIME_LINGER); + if (err != PS_SUCCESS) + return PS_FAIL; + + if (psBrokenDownTimeCmp(&beforeTime, &timeNowLinger) > 0) { + /* beforeTime is in future. */ cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } else if (t.tm_year == (int)y) { - if (t.tm_mon < m) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } else if (t.tm_mon == m && t.tm_mday < d) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } - } - - if (getDateComponents(cert, 1, &y, &m, &d) < 0) { - return PS_FAILURE; - } - if (t.tm_year > (int)y) { + } else if (psBrokenDownTimeCmp(&timeNow, &afterTimeLinger) > 0) { + /* afterTime is in past. */ cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } else if (t.tm_year == (int)y) { - if (t.tm_mon > m) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } else if (t.tm_mon == m && t.tm_mday > d) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } } return 0; -#else - -#ifdef WIN32 - - SYSTEMTIME sysTime; - - GetSystemTime(&sysTime); - if (getDateComponents(cert, 0, &y, &m, &d) < 0) { - return PS_FAILURE; - } - if (sysTime.wYear < (int)y) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } - else if (sysTime.wYear == (int)y) { - if (sysTime.wMonth < m) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } - else if (sysTime.wMonth == m && sysTime.wDay < d) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } - } - if (getDateComponents(cert, 1, &y, &m, &d) < 0) { - return PS_FAILURE; - } - if (sysTime.wYear >(int)y) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } - else if (sysTime.wYear == (int)y) { - if (sysTime.wMonth > m) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } - else if (sysTime.wMonth == m && sysTime.wDay > d) { - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - } - } - return 0; -#else - /* Warn if we are skipping the date validation checks. */ -#warning "CERTIFICATE DATE VALIDITY NOT SUPPORTED ON THIS PLATFORM." - cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; - return 0; -#endif /* WIN32 */ -#endif /* POSIX */ } /******************************************************************************/ /* - Implementation specific date parser. Does not actually verify the date + Implementation specific date parser. */ static int32_t getTimeValidity(psPool_t *pool, const unsigned char **pp, uint16_t len, int32_t *notBeforeTimeType, @@ -3460,6 +3370,8 @@ static int32_t getTimeValidity(psPool_t *pool, const unsigned char **pp, psTraceCrypto("Malformed validity 2\n"); return PS_PARSE_FAIL; } + if (timeLen > MAX_TIME_LEN) + return PS_PARSE_FAIL; *notBefore = psMalloc(pool, timeLen + 1); if (*notBefore == NULL) { psError("Memory allocation error in getTimeValidity for notBefore\n"); @@ -3479,6 +3391,8 @@ static int32_t getTimeValidity(psPool_t *pool, const unsigned char **pp, psTraceCrypto("Malformed validity 4\n"); return PS_PARSE_FAIL; } + if (timeLen > MAX_TIME_LEN) + return PS_PARSE_FAIL; *notAfter = psMalloc(pool, timeLen + 1); if (*notAfter == NULL) { psError("Memory allocation error in getTimeValidity for notAfter\n"); @@ -3718,19 +3632,53 @@ MORE_IN_SET: /* For the known 8-bit character string types, we flag that we want to test for a hidden null in the middle of the string to address the - issue of www.goodguy.com\0badguy.com. For BMPSTRING, the user will - have to validate against the xLen member for such abuses. + issue of www.goodguy.com\0badguy.com. + For validation purposes, BMPSTRINGs are converted to UTF-8 format. */ checkHiddenNull = PS_FALSE; switch (stringType) { + case ASN_BMPSTRING: + { + /* MatrixSSL generally uses single byte character string + formats. This function converts ASN_BMPSTRING to + UTF-8 for further handling. */ + unsigned char *uc_stringOut = NULL; + size_t length; + int32 str_err; + str_err = psToUtf8String(pool, + (const unsigned char *)p, + (size_t)llen, + (psStringType_t)ASN_BMPSTRING, + &uc_stringOut, + &length, +#if DN_NUM_TERMINATING_NULLS == 2 + PS_STRING_DUAL_NIL +#elif DN_NUM_TERMINATING_NULLS == 1 + 0 +#else +#error "Unsupported value for DN_NUM_TERMINATING_NULLS." +#endif + ); + if (str_err != PS_SUCCESS) + return str_err; + /* Length checking. */ + if (length >= 0x7FFE) { + /* Notice if length is too long to fit in 15 bits. */ + psFree(uc_stringOut, pool); + return PS_LIMIT_FAIL; + } + stringOut = (char *) uc_stringOut; + p = p + llen; + llen = (uint16_t) length + DN_NUM_TERMINATING_NULLS; + break; + } case ASN_PRINTABLESTRING: case ASN_UTF8STRING: case ASN_IA5STRING: + case ASN_T61STRING: /* coverity[unterminated_case] */ checkHiddenNull = PS_TRUE; /* fall through */ - case ASN_T61STRING: - case ASN_BMPSTRING: case ASN_BIT_STRING: stringOut = psMalloc(pool, llen + DN_NUM_TERMINATING_NULLS); if (stringOut == NULL) { @@ -4535,92 +4483,6 @@ static int32_t x509ConfirmSignature(const unsigned char *sigHash, /******************************************************************************/ -static unsigned parse_digits(const unsigned char **c_p, - unsigned digits, - unsigned minimum, - unsigned maximum) -{ - const unsigned char *c = *c_p; - unsigned result = 0; - - while(digits) { - if (*c < '0' || *c > '9') - return (unsigned) -1; - result *= 10; - result += *c - '0'; - c++; - digits--; - } - - *c_p = c; - - if (result < minimum || result > maximum) - return (unsigned) -1; - - return result; -} - -/** - Verify a string has (nearly) valid date range format and length. - Optionally output it in struct tm format. - */ -static unsigned char parsedate_ocsp(const unsigned char *p, - unsigned int time_type, - unsigned int time_len, - struct tm *target) -{ - unsigned year, month, mday, hour, min, sec; - const unsigned char *c = p; - if (time_type != ASN_GENERALIZEDTIME) - return 0; - /* Format shall be YYYYMMDDHHMMSSZ (according to RFC 5280). */ - if (time_len != 15) - return 0; - - year = parse_digits(&c, 4, 1900, 2999); - if (year == (unsigned) -1) - return 0; - - month = parse_digits(&c, 2, 1, 12); - if (month == (unsigned) -1) - return 0; - - mday = parse_digits(&c, 2, 1, 31); - if (mday == (unsigned) -1) - return 0; - - hour = parse_digits(&c, 2, 0, 23); - if (hour == (unsigned) -1) - return 0; - - min = parse_digits(&c, 2, 0, 59); - if (min == (unsigned) -1) - return 0; - - /* Allow up-to 2 leap seconds. */ - sec = parse_digits(&c, 2, 0, 61); - if (sec == (unsigned) -1) - return 0; - - /* Time zone must be UTC (Zulu). */ - if (*c != 'Z') - return 0; - - if (target) { - /* Zeroize all fields as some systems have extra fields - in struct tm. */ - memset(target, 0, sizeof(*target)); - target->tm_year = (int) year - 1900; - target->tm_mon = (int) month - 1; - target->tm_mday = (int) mday; - target->tm_hour = (int) hour; - target->tm_min = (int) min; - target->tm_sec = (int) sec; - /* Note: target->tm_wday and target->tm_yday are not set. */ - } - return 1; -} - static int32_t parse_nonce_ext(const unsigned char *p, size_t sz, psBuf_t *nonceExtension) { @@ -4934,7 +4796,7 @@ static int32_t parseBasicOCSPResponse(psPool_t *pool, uint32_t len, return PS_PARSE_FAIL; } /* Perform quick parsing on data. */ - if (parsedate_ocsp(p, ASN_GENERALIZEDTIME, glen, NULL) == 0) + if (psBrokenDownTimeImport(NULL, (const char *) p, glen, 0) < 0) return PS_PARSE_FAIL; res->timeProducedLen = glen; res->timeProduced = p; @@ -5157,7 +5019,7 @@ int32_t parseOCSPResponse(psPool_t *pool, int32_t len, unsigned char **cp, psTraceCrypto("Couldn't parse response in parseOCSPResponse\n"); return PS_PARSE_FAIL; } - if (oi == 117) { + if (oi == OID_BASIC_OCSP_RESPONSE) { /* id-pkix-ocsp-basic BasicOCSPResponse ::= SEQUENCE { @@ -5171,7 +5033,7 @@ int32_t parseOCSPResponse(psPool_t *pool, int32_t len, unsigned char **cp, psTraceCrypto("parseBasicOCSPResponse failure\n"); return PS_PARSE_FAIL; } - } else if (oi == 116) { + } else if (oi == OID_OCSP) { /* id-pkix-ocsp */ psTraceCrypto("unsupported id-pkix-ocsp in parseOCSPResponse\n"); return PS_PARSE_FAIL; @@ -5198,8 +5060,8 @@ int32_t parseOCSPResponse(psPool_t *pool, int32_t len, unsigned char **cp, @param response Pointer to OCSP response structure (from parseOCSPResponse) @param index The index of OCSP single response to handle (0 for the first). - @param timeNow A pointer to structure filled in with gmtime(), structure - initialized to all zero or NULL. + @param timeNow A pointer to structure filled in with psGetBrokenDownGMTime(), + or gmtime(), structure initialized to all zero or NULL. @param producedAt If non-NULL Will be filled in with time the structure was produced. @param thisUpdate If non-NULL Will be filled in with time the OCSP @@ -5217,16 +5079,17 @@ int32_t parseOCSPResponse(psPool_t *pool, int32_t len, unsigned char **cp, */ int32_t checkOCSPResponseDates(mOCSPResponse_t *response, int index, - struct tm *timeNow, - struct tm *producedAt, - struct tm *thisUpdate, - struct tm *nextUpdate, + psBrokenDownTime_t *timeNow, + psBrokenDownTime_t *producedAt, + psBrokenDownTime_t *thisUpdate, + psBrokenDownTime_t *nextUpdate, int time_linger) { - struct tm tmp, tmp2, tmp3, tmp4; + psBrokenDownTime_t tmp, tmp2, tmp3, tmp4; unsigned char ok = 1; int32 err; mOCSPSingleResponse_t *subjectResponse; + psBrokenDownTime_t timeNowLinger; if (index >= MAX_OCSP_RESPONSES) return PS_ARG_FAIL; @@ -5237,14 +5100,16 @@ int32_t checkOCSPResponseDates(mOCSPResponse_t *response, } if (timeNow->tm_year == 0) { - /* The structure appears not filled in, use gmtime() to + /* The structure appears not filled in, use psGetBrokenDownGMTime() to get the current time. */ - time_t time_seconds = time(NULL); - struct tm *new_tm = gmtime(&time_seconds); - if (new_tm == NULL) + err = psGetBrokenDownGMTime(timeNow, 0); + if (err != PS_SUCCESS) return PS_FAIL; - memcpy(timeNow, new_tm, sizeof(struct tm)); } + memcpy(&timeNowLinger, timeNow, sizeof timeNowLinger); + err = psBrokenDownTimeAdd(&timeNowLinger, time_linger); + if (err != PS_SUCCESS) + return PS_FAIL; if (thisUpdate == NULL) thisUpdate = &tmp2; @@ -5255,65 +5120,57 @@ int32_t checkOCSPResponseDates(mOCSPResponse_t *response, if (producedAt == NULL) producedAt = &tmp4; - ok &= parsedate_ocsp(response->timeProduced, - ASN_GENERALIZEDTIME, - response->timeProducedLen, - producedAt); + ok &= psBrokenDownTimeImport(producedAt, + (const char *) response->timeProduced, + response->timeProducedLen, + 0) == PS_SUCCESS; subjectResponse = &response->singleResponse[index]; if (subjectResponse->thisUpdate) - ok &= parsedate_ocsp(subjectResponse->thisUpdate, - ASN_GENERALIZEDTIME, - subjectResponse->thisUpdateLen, - thisUpdate); + ok &= psBrokenDownTimeImport(thisUpdate, + (const char *) subjectResponse->thisUpdate, + subjectResponse->thisUpdateLen, + 0) == PS_SUCCESS; else ok = 0; if (subjectResponse->nextUpdate != NULL) { /* Next update provided, OCSP is valid until that time. */ - ok &= parsedate_ocsp(subjectResponse->nextUpdate, - ASN_GENERALIZEDTIME, - subjectResponse->nextUpdateLen, - nextUpdate); + ok &= psBrokenDownTimeImport(nextUpdate, + (const char *) subjectResponse->nextUpdate, + subjectResponse->nextUpdateLen, + 0) == PS_SUCCESS; } else if (ok) { /* If there is no next update, the server supports continous updates and nextUpdate time is considered identical to the this update time. */ - ok &= parsedate_ocsp(subjectResponse->thisUpdate, - ASN_GENERALIZEDTIME, - subjectResponse->thisUpdateLen, - nextUpdate); + ok &= psBrokenDownTimeImport(nextUpdate, + (const char *) subjectResponse->thisUpdate, + subjectResponse->thisUpdateLen, + 0) == PS_SUCCESS; } if (ok == 1) { - /* Convert times to seconds for comparison. - These also fill in additional fields in tm, like - current day. */ - time_t thisUpdateTime = timegm(thisUpdate); - time_t nextUpdateTime = timegm(nextUpdate); - time_t nextUpdateTimeNew; - time_t nowTime = timegm(timeNow); - (void)timegm(producedAt); + /* Consider linger when comparing nextUpdateTime. */ + psBrokenDownTime_t nextUpdateTimeLinger; + memcpy(&nextUpdateTimeLinger, nextUpdate, sizeof nextUpdateTimeLinger); + err = psBrokenDownTimeAdd(&nextUpdateTimeLinger, time_linger); + if (err != PS_SUCCESS) + return err; - /* Move thisUpdate_time linger seconds back. */ - if (thisUpdateTime > time_linger) - thisUpdateTime -= time_linger; - else - thisUpdateTime = 0; + /* Now check that current time considering linger is between + thisUpdate and nextUpdate. */ - /* Move nextUpdate_time linger seconds to future. - This is not done for times very close to end of - representable time range, such as Y2K38 (on 32-bit - devices). */ - nextUpdateTimeNew = nextUpdateTime + time_linger; - if (nextUpdateTimeNew > nextUpdateTime) - nextUpdateTime = nextUpdateTimeNew; - - if (thisUpdateTime <= nowTime && nowTime <= nextUpdateTime) - err = PS_SUCCESS; - else + if (psBrokenDownTimeCmp(thisUpdate, &timeNowLinger) > 0) { + /* thisUpdate is in future even considering linger => reject. */ err = PS_TIMEOUT_FAIL; + } else if (psBrokenDownTimeCmp(&nextUpdateTimeLinger, timeNow) < 0) { + /* nextUpdate is in past even considering linger => reject. */ + err = PS_TIMEOUT_FAIL; + } else { + /* err has already been set to PS_SUCCESS */ + } } else { err = PS_PARSE_FAIL; } @@ -5322,11 +5179,11 @@ int32_t checkOCSPResponseDates(mOCSPResponse_t *response, /* Diff the current time against the OCSP timestamp and confirm it's not - longer than the user is willing to trust */ + longer than the user is willing to trust. */ static int32_t checkOCSPtimestamp(mOCSPResponse_t *response, int index) { return checkOCSPResponseDates(response, index, NULL, NULL, NULL, NULL, - PS_OCSP_TIME_LINGER); + PS_OCSP_TIME_LINGER); } /* Partial OCSP request parser: just locate nonceExtension if present. */ @@ -5434,7 +5291,7 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, while (ocspResIssuer) { if (memcmp(ocspResIssuer->subject.hash, subject->issuer.hash, 20) == 0) { - + if (psX509AuthenticateCert(pool, subject, ocspResIssuer, &ocspResIssuer, NULL, NULL) == 0) { /* OK, we held the CA that issued the OCSPResponse @@ -5461,7 +5318,7 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, return PS_FAILURE; /* no preloaded CA to auth cert in response */ } } - + /* Issuer will be NULL if there was no certificate attached to the OCSP response. Now look to the user loaded CA files */ if (issuer == NULL) { @@ -5477,7 +5334,7 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, } } } - + /* It is possible a certificate embedded in the server certificate chain was itself the OCSP responder */ if (issuer == NULL) { @@ -5495,22 +5352,22 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, } } } - + if (issuer == NULL) { psTraceCrypto("Unable to locate OCSP responder CA for validation\n"); return PS_FAILURE; } - + /* Now check to see that the response is vouching for the subject cert that we are interested in. The subject will always be the first cert in the server CERTIFICATE chain */ subject = srvCerts; - + /* Now look to match this cert within the singleResponse members. - + There are three components to a CertID that should be used to validate we are looking at the correct OCSP response for the subjecct cert. - + It appears the only "unique" portion of our subject cert that went into the signature of this response is the serial number. The "issuer" information of the subject cert also went into the @@ -5532,17 +5389,18 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, psTraceCrypto("Unable to locate our subject cert in OCSP response\n"); return PS_FAILURE; } - - /* If the response is reporting that this cert is bad right in the status, - just return that immediately and stop the connection */ + if (vOpts->index_p != NULL) { + *(vOpts->index_p) = index; /* Write index of response. */ + } + + /* Obtain general revocation status. */ if (subjectResponse->certStatus == 0) { knownFlag = true; revocationFlag = false; } else if (subjectResponse->certStatus == 1) { knownFlag = true; revocationFlag = true; - /* Server is revoked, but still check rest of - the response. */ + /* certificate is revoked, but still check rest of the response. */ } /* Is the response within the acceptable time window */ @@ -5554,12 +5412,11 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, /* Check if nonces match. */ if (nonceExtReq.buf && vOpts->nonceMatch) { if (response->nonce.buf == NULL) - *(vOpts->nonceMatch) = false; /* No nonce in response. */ + /* No nonce in response. */ + *(vOpts->nonceMatch) = false; else /* Compare nonces. */ - *(vOpts->nonceMatch) = - psBufEq(&nonceExtReq, - &response->nonce); + *(vOpts->nonceMatch) = psBufEq(&nonceExtReq, &response->nonce); } #if 0 /* The issuer here is pointing to the cert that signed the OCSPRespose @@ -5570,7 +5427,7 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, /* Issuer portion of the validation - the subject cert issuer key and name hash should match what the subjectResponse reports - + POSSIBLE PROBLEMS: Only supporting a SHA1 hash here. The MatrixSSL parser will only use SHA1 for the DN and key hash. Just warning on this for now. The signature validation will catch any key mismatch */ @@ -5591,7 +5448,6 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, } #endif /* 0 */ - /* Finally do the sig validation */ switch (response->sigAlg) { #ifdef USE_SHA256 @@ -5626,7 +5482,7 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, /* Should have been caught in parse phase */ return PS_UNSUPPORTED_FAIL; } - + /* Finally test the signature */ if (sigType == PS_RSA) { if (issuer->publicKey.type != PS_RSA) { @@ -5662,7 +5518,7 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, } } #endif - + if (vOpts->knownFlag) *(vOpts->knownFlag) = knownFlag; @@ -5674,12 +5530,10 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, *(vOpts->revocationFlag) = revocationFlag; if (vOpts->revocationTime) { - if (parsedate_ocsp( - subjectResponse->revocationTime, - ASN_GENERALIZEDTIME, - sizeof(subjectResponse->revocationTime), - vOpts->revocationTime)) - (void)timegm(vOpts->revocationTime); + (void)psBrokenDownTimeImport( + vOpts->revocationTime, + (const char *) subjectResponse->revocationTime, + sizeof(subjectResponse->revocationTime), 0); } if (vOpts->revocationReason) @@ -5688,7 +5542,7 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, /* Function fails if certificate was revoked. */ if (revocationFlag) - return PS_FAILURE; + return PS_CERT_AUTH_FAIL_REVOKED; } /* Was able to successfully confirm OCSP signature for our subject */ @@ -5696,12 +5550,17 @@ int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, } int32_t validateOCSPResponse(psPool_t *pool, psX509Cert_t *trustedOCSP, - psX509Cert_t *srvCerts, - mOCSPResponse_t *response) { - return validateOCSPResponse_ex(pool, trustedOCSP, srvCerts, response, - NULL); + psX509Cert_t *srvCerts, + mOCSPResponse_t *response) { + return validateOCSPResponse_ex(pool, trustedOCSP, srvCerts, response, NULL); } +void uninitOCSPResponse(mOCSPResponse_t *res) { + psX509FreeCert(res->OCSPResponseCert); + memset(res, 0, sizeof(*res)); +} + + #endif /* USE_OCSP */ #endif /* USE_X509 */ diff --git a/crypto/keyformat/x509.h b/crypto/keyformat/x509.h index 5e2d9e4..61d2478 100644 --- a/crypto/keyformat/x509.h +++ b/crypto/keyformat/x509.h @@ -50,6 +50,16 @@ enum { ECDSA_FIXED_ECDH }; +/* The default value of allowed mismatch in times in X.509 messages and the + local clock. The default value of 24 hours is mostly equivalent to old + MatrixSSL behavior of ignoring hours, minutes and seconds in X.509 date + comparison. Note: There is different value for CRL (PS_CRL_TIME_LINGER) and OCSP + (PS_OCSP_TIME_LINGER). */ +#define PS_X509_TIME_LINGER (24 * 60 * 60) +/* This is approximately equivalent to old MatrixSSL behavior of + only comparing date. */ +#define PS_CRL_TIME_LINGER (24 * 60 * 60) + /* Parsing flags */ #define CERT_STORE_UNPARSED_BUFFER 0x1 #define CERT_STORE_DN_BUFFER 0x2 @@ -172,19 +182,21 @@ typedef struct { int32 pathLenConstraint; } x509extBasicConstraints_t; + typedef enum { + GN_OTHER = 0, // OtherName + GN_EMAIL, // IA5String + GN_DNS, // IA5String + GN_X400, // ORAddress + GN_DIR, // Name + GN_EDI, // EDIPartyName + GN_URI, // IA5String + GN_IP, // OCTET STRING + GN_REGID // OBJECT IDENTIFIER + } x509GeneralNameType_t; + typedef struct psGeneralNameEntry { psPool_t *pool; - enum { - GN_OTHER = 0, // OtherName - GN_EMAIL, // IA5String - GN_DNS, // IA5String - GN_X400, // ORAddress - GN_DIR, // Name - GN_EDI, // EDIPartyName - GN_URI, // IA5String - GN_IP, // OCTET STRING - GN_REGID // OBJECT IDENTIFIER - } id; + x509GeneralNameType_t id; unsigned char name[16]; unsigned char oid[32]; /* SubjectAltName OtherName */ unsigned char *data; @@ -533,6 +545,16 @@ typedef struct psCRL { typedef struct psCert { psPool_t *pool; + int32 sigAlgorithm; /* Certificate sig alg OID */ + int32 certAlgorithm; /* TBSCertificate sig alg OID */ + unsigned char *signature; + uint16_t signatureLen; +#ifdef USE_PKCS1_PSS + int32 pssHash; /* RSAPSS sig hash OID */ + int32 maskGen; /* RSAPSS maskgen OID */ + int32 maskHash; /* hash OID for MGF1 */ + uint16_t saltLen; /* RSAPSS salt len param */ +#endif /* USE_PKCS1_PSS */ #ifdef USE_CERT_PARSE psPubKey_t publicKey; int32 version; @@ -545,18 +567,8 @@ typedef struct psCert { char *notBefore; char *notAfter; int32 pubKeyAlgorithm; /* public key algorithm OID */ - int32 certAlgorithm; /* signature algorithm OID */ - int32 sigAlgorithm; /* signature algorithm OID */ -#ifdef USE_PKCS1_PSS - int32 pssHash; /* RSAPSS sig hash OID */ - int32 maskGen; /* RSAPSS maskgen OID */ - int32 maskHash; /* hash OID for MGF1 */ - uint16_t saltLen; /* RSAPSS salt len param */ -#endif - unsigned char *signature; unsigned char *uniqueIssuerId; unsigned char *uniqueSubjectId; - uint16_t signatureLen; uint16_t uniqueIssuerIdLen; uint16_t uniqueSubjectIdLen; x509v3extensions_t extensions; @@ -582,9 +594,9 @@ typedef struct psCert { } psX509Cert_t; -#ifdef USE_CERT_PARSE extern int32_t psX509GetSignature(psPool_t *pool, const unsigned char **pp, uint16_t len, unsigned char **sig, uint16_t *sigLen); +#ifdef USE_CERT_PARSE extern int32_t psX509GetDNAttributes(psPool_t *pool, const unsigned char **pp, uint16_t len, x509DNattributes_t *attribs, uint32_t flags); extern void psX509FreeDNStruct(x509DNattributes_t *dn, psPool_t *allocPool); @@ -694,41 +706,85 @@ typedef struct { be provided. */ bool *nonceMatch; /* Will indicate revocation time (note: timezone = UTC). */ - struct tm *revocationTime; + psBrokenDownTime_t *revocationTime; /* Will indicate revocation reason. */ x509CrlReason_t *revocationReason; + /* The request for comparing nonce if nonce extension is used. */ const void *request; size_t requestLen; + /* The location for use response index. */ + int32 *index_p; } psValidateOCSPResponseOptions_t; +/* Parse OCSP response received. + The result shall be unitialized with uninitOCSPResponse(). */ extern int32_t parseOCSPResponse(psPool_t *pool, int32_t len, unsigned char **cp, unsigned char *end, mOCSPResponse_t *response); +/* Get dates from OCSP response, to e.g. check how long server wants the + response to remain valid. */ extern int32_t checkOCSPResponseDates(mOCSPResponse_t *response, int index, - struct tm *time_now, - struct tm *producedAt, - struct tm *thisUpdate, - struct tm *nextUpdate, + psBrokenDownTime_t *time_now, + psBrokenDownTime_t *producedAt, + psBrokenDownTime_t *thisUpdate, + psBrokenDownTime_t *nextUpdate, int time_linger); +/* Validate OCSP response (find status of specific certificate) */ extern int32_t validateOCSPResponse(psPool_t *pool, psX509Cert_t *trustedOCSP, - psX509Cert_t *srvCerts, mOCSPResponse_t *response); -extern int32_t validateOCSPResponse_ex(psPool_t *pool, psX509Cert_t *trustedOCSP, - psX509Cert_t *srvCerts, mOCSPResponse_t *response, psValidateOCSPResponseOptions_t *vOpts); + psX509Cert_t *srvCerts, + mOCSPResponse_t *response); + +/* Validation with additional parameter to obtain more details, like + revocation time and reason. */ +extern int32_t validateOCSPResponse_ex(psPool_t *pool, + psX509Cert_t *trustedOCSP, + psX509Cert_t *srvCerts, + mOCSPResponse_t *response, + psValidateOCSPResponseOptions_t *vOpts); + +/* Construct OCSP request used in OCSP protocol to obtain OCSP response. + The request obtained typically needs to be sent to OCSP responder using + HTTP protocol to obtain corresponding OCSP response. + After finished with the request, it shall be freed using psFree(). */ extern int32_t matrixSslWriteOCSPRequest(psPool_t *pool, psX509Cert_t *cert, psX509Cert_t *certIssuer, unsigned char **request, uint32_t *requestLen, int32_t flags); +/* Uninitialize OCSP response. */ +void uninitOCSPResponse(mOCSPResponse_t *res); + typedef struct { int32_t flags; - const psBuf_t *requesterId; /* Optional requestor id. */ + psBuf_t *requesterId; /* Optional requestor id. */ const psBuf_t *requestExtensions; /* Optional request extensions. */ } matrixSslWriteOCSPRequestInfo_t; -#define MATRIXSSL_WRITE_OCSP_REQUEST_FLAG_NONCE 1 /* Use nonce. */ +/* Set Requester ID for matrixSslWriteOCSPRequestInfo_t structure. + It shall be freed using matrixSslWriteOCSPRequestInfoFreeRequestorId. + The data expected varies according to the general name, for instance, for + IPv4 address, the data shall be array of 4 bytes containing the octets. + However, for the most types the data shall be a string, and for this reason + parameters are called str and strLen. + For GN_DIR, the octet sequence can be created with psWriteCertDNAttributes() + function. */ +extern int32_t matrixSslWriteOCSPRequestInfoSetRequestorId( + psPool_t *pool, + matrixSslWriteOCSPRequestInfo_t *info, + const char *str, size_t strLen, x509GeneralNameType_t type); +/* Free previously set Requester ID from matrixSslWriteOCSPRequestInfo_t + structure. */ +extern void matrixSslWriteOCSPRequestInfoFreeRequestorId( + psPool_t *pool, matrixSslWriteOCSPRequestInfo_t *info); + +#define MATRIXSSL_WRITE_OCSP_REQUEST_FLAG_NONCE 1 /* Use nonce. */ +#define MATRIXSSL_WRITE_OCSP_REQUEST_FLAG_CERT_LIST 2 /* Multiple requests. */ + +/* Extended version of matrixSslWriteOCSPRequest: allows use of + requestor name and nonce extension. */ extern int32_t matrixSslWriteOCSPRequestExt( psPool_t *pool, psX509Cert_t *cert, psX509Cert_t *certIssuer, unsigned char **request, diff --git a/crypto/math/pstm.c b/crypto/math/pstm.c index 9022bda..34d62e2 100644 --- a/crypto/math/pstm.c +++ b/crypto/math/pstm.c @@ -32,6 +32,9 @@ */ /******************************************************************************/ +/* This pstm mathematics library is + based on libraries by Tom St Denis. */ + #include "../cryptoApi.h" #include /* toupper() */ @@ -1394,6 +1397,106 @@ static uint64 psDiv128(uint128 *numerator, uint64 denominator) } #endif /* USE_MATRIX_DIV128 */ +#ifndef PSTM_LARGE_DIV + +/* This version of division uses short & small function, but offers + bit worse performance than some others. */ +int pstm_div(psPool_t *pool, const pstm_int *a, const pstm_int *b, + pstm_int *c, pstm_int *d) +{ + pstm_int ta, tb, tq, q; + int res, n, n2; + + /* is divisor zero ? */ + if (pstm_iszero(b) == PSTM_YES) { + return PS_LIMIT_FAIL; + } + + /* if a < b then q=0, r = a */ + if (pstm_cmp_mag(a, b) == PSTM_LT) { + if (d != NULL) { + res = pstm_copy(a, d); + } else { + res = PSTM_OKAY; + } + if (c != NULL) { + pstm_zero(c); + } + return res; + } + + /* init our temps */ + res = pstm_init(pool, &ta); + if (res != PSTM_OKAY) { + return res; + } + res = pstm_init(pool, &tb); + if (res != PSTM_OKAY) { + pstm_clear(&ta); + return res; + } + res = pstm_init(pool, &tq); + if (res != PSTM_OKAY) { + pstm_clear(&ta); + pstm_clear(&tb); + return res; + } + res = pstm_init(pool, &q); + if (res != PSTM_OKAY) { + pstm_clear(&ta); + pstm_clear(&tb); + pstm_clear(&tq); + return res; + } + + pstm_set(&tq, 1); + n = pstm_count_bits(a) - pstm_count_bits(b); + if (((res = pstm_abs(a, &ta)) != PSTM_OKAY) || + ((res = pstm_abs(b, &tb)) != PSTM_OKAY) || + ((res = pstm_mul_2d(&tb, n, &tb)) != PSTM_OKAY) || + ((res = pstm_mul_2d(&tq, n, &tq)) != PSTM_OKAY)) { + goto LBL_ERR; + } + + while (n-- >= 0) { + if (pstm_cmp(&tb, &ta) != PSTM_GT) { + if (((res = pstm_sub(&ta, &tb, &ta)) != PSTM_OKAY) || + ((res = pstm_add(&q, &tq, &q)) != PSTM_OKAY)) { + goto LBL_ERR; + } + } + if (((res = pstm_div_2d(pool, &tb, 1, &tb, NULL)) != + PSTM_OKAY) || + ((res = pstm_div_2d(pool, &tq, 1, &tq, NULL)) != + PSTM_OKAY)) { + goto LBL_ERR; + } + } + + /* now q == quotient and ta == remainder */ + n = a->sign; + n2 = (a->sign == b->sign) ? PSTM_ZPOS : PSTM_NEG; + if (c != NULL) { + pstm_exch(c, &q); + c->sign = (pstm_iszero(c) == PSTM_YES) ? PSTM_ZPOS : n2; + } + if (d != NULL) { + pstm_exch(d, &ta); + d->sign = (pstm_iszero(d) == PSTM_YES) ? PSTM_ZPOS : n; + } +LBL_ERR: + pstm_clear (&ta); + pstm_clear (&tb); + pstm_clear (&tq); + pstm_clear (&q); + return res; +} + +#else /* defined PSTM_LARGE_DIV */ + +/* This noticed is accompanied with this function to discourage its use. */ +#warning "This function has been noticed to give wrong results for some inputs." + /******************************************************************************/ /** c = a / b, d = remainder. @@ -1404,11 +1507,11 @@ static uint64 psDiv128(uint128 *numerator, uint64 denominator) @param[out] c The result @param[out] d If non-NULL, the remainder of the division is stored here @return < 0 on failure - + a/b => cb + d == a */ -int32_t pstm_div(psPool_t *pool, const pstm_int *a, const pstm_int *b, pstm_int *c, - pstm_int *d) +int32_t pstm_div(psPool_t *pool, const pstm_int *a, const pstm_int *b, + pstm_int *c, pstm_int *d) { pstm_int q, x, y, t1, t2; int32_t res; @@ -1441,7 +1544,8 @@ int32_t pstm_div(psPool_t *pool, const pstm_int *a, const pstm_int *b, pstm_int if ((res = pstm_init_copy(pool, &x, a, 0)) != PSTM_OKAY) { goto LBL_T2; } - /* Used to be an init_copy on b but pstm_grow was always hit with triple size */ + /* Used to be an init_copy on b but pstm_grow was always hit with triple + size */ if ((res = pstm_init_size(pool, &y, b->used * 3)) != PSTM_OKAY) { goto LBL_X; } @@ -1610,6 +1714,7 @@ LBL_T1:pstm_clear (&t1); return res; } +#endif /* PSTM_LARGE_DIV */ /******************************************************************************/ /* @@ -1651,7 +1756,7 @@ int32_t pstm_mod(psPool_t *pool, const pstm_int *a, const pstm_int *b, pstm_int return err; } -#ifdef USE_MATRIX_RSA +#if defined USE_MATRIX_RSA || defined USE_MATRIX_ECC || defined USE_MATRIX_DH /******************************************************************************/ /* d = a * b (mod c) @@ -1937,7 +2042,7 @@ LBL_M: pstm_clear(&M[1]); LBL_RES:pstm_clear(&res); return err; } -#endif /* USE_MATRIX_RSA */ +#endif /* USE_MATRIX_RSA || USE_MATRIX_ECC || USE_MATRIX_DH */ /******************************************************************************/ /** diff --git a/crypto/math/pstm.h b/crypto/math/pstm.h index fd74fbd..d49ece3 100644 --- a/crypto/math/pstm.h +++ b/crypto/math/pstm.h @@ -125,6 +125,11 @@ #define PSTM_OKAY PS_SUCCESS #define PSTM_MEM PS_MEM_FAIL +/* replies */ +#define PSTM_YES 1 /* yes response */ +#define PSTM_NO 0 /* no response */ + + /******************************************************************************/ /* This is the maximum size that pstm_int.alloc can be for crypto operations. Effectively, it is three times the size of the largest private key. */ diff --git a/crypto/prng/yarrow.c b/crypto/prng/yarrow.c index d8ec44f..fc55d02 100644 --- a/crypto/prng/yarrow.c +++ b/crypto/prng/yarrow.c @@ -35,6 +35,13 @@ #include "../cryptoApi.h" #ifdef USE_YARROW + +#ifdef WIN32 +#pragma message("THIS CODE IS DEPRECATED. PLEASE CONNECT psGetEntropy() directly to a TRNG or PRNG.") +#else +#warning "THIS CODE IS DEPRECATED. PLEASE CONNECT psGetEntropy() directly to a TRNG or PRNG." +#endif + /******************************************************************************/ /* A basic yarrow implementation hardcoded to AES and SHA. Only one @@ -72,7 +79,11 @@ int32 psYarrowStart(psYarrow_t *ctx) */ int32 psYarrowAddEntropy(unsigned char *in, uint32 inlen, psYarrow_t *prng) { - psDigestContext_t md; +#ifdef USE_SHA256 + psSha256_t md; +#else + psSha1_t md; +#endif int32 err; if (in == NULL || prng == NULL) { @@ -81,6 +92,7 @@ int32 psYarrowAddEntropy(unsigned char *in, uint32 inlen, psYarrow_t *prng) #ifdef USE_SHA256 /* start the hash */ + psSha256PreInit(&md); psSha256Init(&md); /* hash the current pool */ @@ -90,11 +102,10 @@ int32 psYarrowAddEntropy(unsigned char *in, uint32 inlen, psYarrow_t *prng) psSha256Update(&md, in, inlen); /* store result */ - if ((err = psSha256Final(&md, prng->pool)) != SHA256_HASH_SIZE) { - return err; - } + psSha256Final(&md, prng->pool); #else /* start the hash */ + psSha1PreInit(&md); psSha1Init(&md); /* hash the current pool */ @@ -104,9 +115,7 @@ int32 psYarrowAddEntropy(unsigned char *in, uint32 inlen, psYarrow_t *prng) psSha1Update(&md, in, inlen); /* store result */ - if ((err = psSha1Final(&md, prng->pool)) != SHA1_HASH_SIZE) { - return err; - } + psSha1Final(&md, prng->pool); #endif return PS_SUCCESS; } @@ -136,7 +145,8 @@ int32 psYarrowReseed(psYarrow_t *ctx) } /* setup cipher */ - if ((err = psAesInitBlockKey(ctx->pool, keylen, &ctx->key)) != PS_SUCCESS) { + if ((err = psAesInitBlockKey(&ctx->key, ctx->pool, keylen, + PS_AES_ENCRYPT)) != PS_SUCCESS) { return err; } @@ -166,7 +176,7 @@ int32 psYarrowReseed(psYarrow_t *ctx) } } - psAesEncryptBlock(ctx->ctr, ctx->pad, &ctx->key); + psAesEncryptBlock(&ctx->key, ctx->ctr, ctx->pad); return PS_SUCCESS; } @@ -221,7 +231,7 @@ uint32 psYarrowRead(unsigned char *out, uint32 outlen, psYarrow_t *ctx) } /* encrypt new pad and reset */ - psAesEncryptBlock(ctx->ctr, ctx->pad, &ctx->key); + psAesEncryptBlock(&ctx->key, ctx->ctr, ctx->pad); ctx->padlen = 0; } *ct++ = *pt++ ^ ctx->pad[ctx->padlen++]; diff --git a/crypto/pubkey/pubkey.c b/crypto/pubkey/pubkey.c index 3184126..55a0c33 100644 --- a/crypto/pubkey/pubkey.c +++ b/crypto/pubkey/pubkey.c @@ -109,6 +109,7 @@ void psDeletePubKey(psPubKey_t **key) *key = NULL; } +#ifdef USE_PRIVATE_KEY_PARSING #ifdef MATRIX_USE_FILE_SYSTEM #if defined(USE_ECC) && defined(USE_RSA) /* Trial and error private key parse for when ECC or RSA is unknown. @@ -199,6 +200,7 @@ parsed: } #endif /* USE_ECC && USE_RSA */ #endif /* MATRIX_USE_FILE_SYSTEM */ +#endif /* USE_PRIVATE_KEY_PARSING */ /******************************************************************************/ diff --git a/crypto/pubkey/rsa.c b/crypto/pubkey/rsa.c index fa44a8d..ee9b8f8 100644 --- a/crypto/pubkey/rsa.c +++ b/crypto/pubkey/rsa.c @@ -329,6 +329,7 @@ int32_t psRsaParseAsnPubKey(psPool_t *pool, psDigestContext_t dc; #endif const unsigned char *p = *pp; + const unsigned char *end; uint16_t keylen, seqlen; if (len < 1 || (*(p++) != ASN_BIT_STRING) || @@ -339,7 +340,9 @@ int32_t psRsaParseAsnPubKey(psPool_t *pool, if (*p++ != 0) { goto L_FAIL; } - + if (keylen < 1) { + goto L_FAIL; + } #ifdef USE_SHA1 /* A public key hash is used in PKI tools (OCSP, Trusted CA indication). Standard RSA form - SHA-1 hash of the value of the BIT STRING @@ -351,9 +354,13 @@ int32_t psRsaParseAsnPubKey(psPool_t *pool, psSha1Final(&dc.sha1, sha1KeyHash); #endif - if (getAsnSequence(&p, keylen, &seqlen) < 0 || - pstm_read_asn(pool, &p, seqlen, &key->N) < 0 || - pstm_read_asn(pool, &p, seqlen, &key->e) < 0) { + if (getAsnSequence(&p, keylen, &seqlen) < 0) { + goto L_FAIL; + } + + end = p + seqlen; + if (pstm_read_asn(pool, &p, (uint16_t) (end - p), &key->N) < 0 || + pstm_read_asn(pool, &p, (uint16_t) (end - p), &key->e) < 0) { goto L_FAIL; } diff --git a/crypto/test/algorithmTest.c b/crypto/test/algorithmTest.c index dde1256..064c7ef 100644 --- a/crypto/test/algorithmTest.c +++ b/crypto/test/algorithmTest.c @@ -2599,8 +2599,12 @@ int32 psMd5Test(void) psMd5_t md; for (i = 0; tests[i].msg != NULL; i++) { - _psTraceInt(" MD5 known vector test %d... ", i + 1); - psMd5Init(&md); + _psTraceInt(" MD5 known vector test %d... ", i + 1); + psMd5PreInit(&md); + if (psMd5Init(&md) < 0) { + _psTrace("FAILED: psMd5Init\n"); + return -1; + } psMd5Update(&md, (unsigned char *)tests[i].msg, (uint32)strlen(tests[i].msg)); psMd5Final(&md, tmp); @@ -2706,10 +2710,17 @@ int32 psMd2Test(void) for (i = 0; i < (int32)(sizeof(tests) / sizeof(tests[0])); i++) { _psTraceInt(" MD2 known vector test %d... ", i + 1); + psMd2PreInit(&md); psMd2Init(&md); - psMd2Update(&md, (unsigned char*)tests[i].msg, - (uint32)strlen(tests[i].msg)); - psMd2Final(&md, buf); + if (psMd2Update(&md, (unsigned char*)tests[i].msg, + (uint32)strlen(tests[i].msg)) < 0) { + _psTrace("FAILED: psMd2Update\n"); + return -1; + } + if (psMd2Final(&md, buf) < 0) { + _psTrace("FAILED: psMd2Final\n"); + return -1; + } if (memcmp(buf, tests[i].md, 16) != 0) { _psTrace("FAILED: memcmp\n"); return -1; @@ -2724,6 +2735,7 @@ int32 psMd2Test(void) /******************************************************************************/ #ifdef USE_RSA +#ifdef USE_PRIVATE_KEY_PARSING typedef void pkaCmdInfo_t; @@ -2864,7 +2876,7 @@ static int32 psRsaSignTest(void) return PS_SUCCESS; } - +#endif /* USE_PRIVATE_KEY_PARSING */ /******************************************************************************/ #ifdef USE_PKCS1_OAEP @@ -3370,6 +3382,7 @@ LBL_ERR: static int nohmactls = 0; #endif +#ifdef USE_HMAC_SHA1 static int32 psHmacVectorTestSimple(void) { unsigned char res[20]; @@ -3439,6 +3452,7 @@ static int32 psHmacVectorTestSimple(void) _psTrace("PASSED\n"); return PS_SUCCESS; } +#endif /* USE_HMAC_SHA1 */ static int test_hmac_vector_num_calls; @@ -3456,9 +3470,15 @@ static int test_hmac_vector(int32 size, uint16_t key_length = 0; int equals; int32 rv = PS_SUCCESS; +#ifdef USE_HMAC_SHA1 psHmacSha1_t hmac_sha1_ctx; +#endif /* USE_HMAC_SHA1 */ +#ifdef USE_HMAC_SHA256 psHmacSha256_t hmac_sha256_ctx; +#endif /* USE_HMAC_SHA256 */ +#ifdef USE_HMAC_SHA384 psHmacSha384_t hmac_sha384_ctx; +#endif /* USE_HMAC_SHA384 */ ++test_hmac_vector_num_calls; @@ -3472,22 +3492,31 @@ static int test_hmac_vector(int32 size, psAssert(size == 20 || size == 28 || size == 32 || size == 48); +#ifdef USE_HMAC_SHA1 if (size == 20) { rv = psHmacSha1((unsigned char *) key, key_length, din, din_len, md_res, key_out, &key_length); - } else if (size == 32) { + } else +#endif /* USE_HMAC_SHA1 */ +#ifdef USE_HMAC_SHA256 + if (size == 32) { rv = psHmacSha256((unsigned char *) key, key_length, din, din_len, md_res, key_out, &key_length); - } else if (size == 48) { + } else +#endif /* USE_HMAC_SHA256 */ +#ifdef USE_HMAC_SHA384 + if (size == 48) { rv = psHmacSha384((unsigned char *) key, key_length, din, din_len, md_res, key_out, &key_length); - } else { + } else +#endif /* USE_HMAC_SHA384 */ + { _psTraceInt("FAILED: HMAC vector unsupported size: %d\n", (int) size); return PS_FAILURE; @@ -3504,19 +3533,27 @@ static int test_hmac_vector(int32 size, memset(md_res, 0, sizeof(md_res)); +#ifdef USE_HMAC_SHA1 if (size == 20) { rv = psHmacSha1Init(&hmac_sha1_ctx, key_out, key_length); psHmacSha1Update(&hmac_sha1_ctx, din, din_len); psHmacSha1Final(&hmac_sha1_ctx, md_res); - } else if (size == 32) { + } else +#endif /* USE_HMAC_SHA1 */ +#ifdef USE_HMAC_SHA256 + if (size == 32) { rv = psHmacSha256Init(&hmac_sha256_ctx, key_out, key_length); psHmacSha256Update(&hmac_sha256_ctx, din, din_len); psHmacSha256Final(&hmac_sha256_ctx, md_res); - } else if (size == 48) { + } else +#endif /* USE_HMAC_SHA256 */ +#ifdef USE_HMAC_SHA384 + if (size == 48) { rv = psHmacSha384Init(&hmac_sha384_ctx, key_out, key_length); psHmacSha384Update(&hmac_sha384_ctx, din, din_len); psHmacSha384Final(&hmac_sha384_ctx, md_res); } +#endif /* USE_HMAC_SHA384 */ equals = (rv == PS_SUCCESS && memcmp(dout, md_res, size) == 0); if (equals != should_succeed) @@ -4290,22 +4327,29 @@ sha_finish: return res; } +#ifdef USE_HMAC_SHA1 static int32 psHmacVectorTestsSHA1(void) { return psHmacVectorTestsShared(20); } +#endif /* USE_HMAC_SHA1 */ +#ifdef USE_HMAC_SHA256 static int32 psHmacVectorTestsSHA256(void) { return psHmacVectorTestsShared(32); } +#endif /* USE_HMAC_SHA256 */ +#ifdef USE_HMAC_SHA384 static int32 psHmacVectorTestsSHA384(void) { return psHmacVectorTestsShared(48); } +#endif /* USE_HMAC_SHA384 */ +#ifdef USE_HMAC_SHA1 static int32 psHmacVectorTestsSimultaneous(void) { psHmacSha1_t ctx1; @@ -4365,25 +4409,43 @@ static int32 psHmacVectorTestsSimultaneous(void) _psTrace("PASSED\n"); return PS_SUCCESS; } - +#endif /* USE_HMAC_SHA1 */ static int32 psHmacVectorTests(void) { int32 res; +#ifdef USE_HMAC_SHA1 res = psHmacVectorTestSimple(); +#endif /* USE_HMAC_SHA1 */ _psTraceInt(" SHA-1 known vector test %d... ", 2); +#ifdef USE_HMAC_SHA1 res |= psHmacVectorTestsSHA1(); +#else + _psTrace("SKIPPED.\n"); +#endif /* USE_HMAC_SHA1 */ _psTraceInt(" SHA-256 known vector test %d... ", 1); +#ifdef USE_HMAC_SHA256 res |= psHmacVectorTestsSHA256(); +#else + _psTrace("SKIPPED.\n"); +#endif /* USE_HMAC_SHA256 */ _psTraceInt(" SHA-384 known vector test %d... ", 1); +#ifdef USE_HMAC_SHA384 res |= psHmacVectorTestsSHA384(); +#else + _psTrace("SKIPPED.\n"); +#endif /* USE_HMAC_SHA384 */ _psTrace(" Simultaneous hmac contexts... "); +#ifdef USE_HMAC_SHA1 res |= psHmacVectorTestsSimultaneous(); +#else + _psTrace("SKIPPED.\n"); +#endif /* USE_HMAC_SHA1 */ return res; } @@ -4954,14 +5016,14 @@ static test_t tests[] = { {psPrngTests , "***** PRNG TESTS *****"}, -#ifdef USE_RSA +#if defined(USE_RSA) && defined(USE_PRIVATE_KEY_PARSING) {psRsaEncryptTest #else {NULL #endif , "***** RSA ENCRYPT TESTS *****"}, -#ifdef USE_RSA +#if defined(USE_RSA) && defined(USE_PRIVATE_KEY_PARSING) {psRsaSignTest #else {NULL diff --git a/crypto/test/rsaperf/rsaperf.c b/crypto/test/rsaperf/rsaperf.c index 7a86ed7..da74685 100644 --- a/crypto/test/rsaperf/rsaperf.c +++ b/crypto/test/rsaperf/rsaperf.c @@ -35,6 +35,8 @@ #include /* sleep */ #include "crypto/cryptoApi.h" +#if defined(USE_RSA) && defined(USE_PRIVATE_KEY_PARSING) + typedef void pkaCmdInfo_t; /* OPERATIONS TO TEST */ @@ -538,3 +540,15 @@ int main(int argc, char **argv) psCryptoClose(); return 0; } +#else /* --> !USE_RSA || !USE_PRIVATE_KEY_PARSING*/ +int main(int argc, char **argv) +{ +#ifndef USE_RSA + _psTrace("Please enable USE_RSA for this test\n"); +#endif /* USE_RSA */ +#ifndef USE_PRIVATE_KEY_PARSING + _psTrace("Please enable USE_PRIVATE_KEY_PARSING for this test\n"); +#endif /* USE_PRIVATE_KEY_PARSING */ + return 1; +} +#endif /* USE_RSA && USE_PRIVATE_KEY_PARSING */ diff --git a/doc/matrixssl_dev_guide.md b/doc/matrixssl_dev_guide.md index 6011833..05461d2 100644 --- a/doc/matrixssl_dev_guide.md +++ b/doc/matrixssl_dev_guide.md @@ -745,12 +745,10 @@ MatrixSSL contains a set of optional debug features that are configurable at com : matrixsslConfig.h - If enabled, each DTLS handshake message will be returned individually when matrixDtlsGetOutdata is called. When left disabled, the default behaviour of matrixDtlsGetOutdata is to return as much data as possible that fits within the maximum PMTU. ##4.4 Minimum Firmware Configuration -MatrixSSL can be built to a minimum size using TLS 1.2, PSK cipher with AES128 and SHA256. If interoperability with *OpenSSL* is desired, this standard cipher suite is not implemented (as of 1.0.1j). In this case, `USE_SHA` must also be defined and the cipher suite changed to +MatrixSSL can be built to a minimum size using TLS 1.2, PSK cipher with AES128 and SHA256. If interoperability with *OpenSSL* is desired, then a few changes are necessary, since the USE_TLS_PSK_WITH_AES_128_CBC_SHA256 ciphersuite is not implemented by OpenSSL (as of 1.0.2d). In this case, `USE_SHA1` and `USE_HMAC_SHA1` must also be defined and the cipher suite changed to `USE_TLS_PSK_WITH_AES_256_CBC_SHA` or `USE_TLS_PSK_WITH_AES_128_CBC_SHA`. -_The MatrixSSL Performance Guide_ has more information on storage and memory requirements for various configurations and platforms. - To enable minimal configuration, all options in _core/coreConfig.h_, _crypto/cryptoConfig.h_ and _matrixssl/matrixsslConfig.h_ should be commented out, except for the following: _coreConfig.h_ @@ -758,14 +756,13 @@ _coreConfig.h_ Optional: Disable `USE_CORE_ERROR` and `USE_CORE_ASSERT` _cryptoConfig.h_ -: `USE_AES`, `USE_SHA256`, `USE_HMAC` +: `USE_AES_CBC`, `USE_SHA256`, `USE_HMAC`, `USE_HMAC_SHA256` Optional: `__AES__` block to enable *AESNI* on *Intel* platforms. -Optional: For *OpenSSL* compatibility, also enable `USE_SHA1` +Optional: For *OpenSSL* compatibility, also enable `USE_SHA1` and `USE_HMAC_SHA1` _matrixsslConfig.h_ : `USE_TLS_PSK_WITH_AES_128_CBC_SHA256` -`USE_TLS`, `USE_TLS_1_1`, `USE_TLS_1_2`, `DISABLE_TLS_1_1`, `DISABLE_TLS_1_0`, `DISABLE_SSLV3` -`USE_CLIENT_SIDE_SSL` and/or `USE_SERVER_SIDE_SSL` +`USE_TLS_1_2_AND_ABOVE`, `USE_CLIENT_SIDE_SSL` and/or `USE_SERVER_SIDE_SSL` Optional: `SSL_DEFAULT_IN_BUF_SIZE`, `SSL_DEFAULT_OUT_BUF_SIZE` set to 1500 for reduced RAM footprint. Optional for Server: `SSL_SESSION_TABLE_SIZE` as low as 1 for reduced RAM footprint. Optional: `USE_DTLS` @@ -790,8 +787,8 @@ nonfips|Same as default noecc|Disables ECC support rsaonly|Disables ECC and DH support tls|The recommended configuration for TLS - -These configurations can be applied with the commands _make all-nonfips_, _make all-noecc_, _make all-rsaonly_ and _make all-tls_, respectively. Applying a new configuration will override the existing _./core/coreConfig.h_, _./crypto/cryptoConfig.h_, and _./matrixssl/matrixsslConfig.h_ files. After applying the configuration, these files can be further adapted per specific needs and the MatrixSSL can be compiled as usual, via the make commands described in the _MatrixSSL Getting Started_ document. +nonfips-psk|The minimal PSK configuration described in the last subsection, except that both server- and client side support are enabled. +These configurations can be applied with the commands _make all-nonfips_, _make all-noecc_, _make all-rsaonly_, _make all-tls_, _make all-nonfips-psk_ respectively. Applying a new configuration will override the existing _./core/coreConfig.h_, _./crypto/cryptoConfig.h_, and _./matrixssl/matrixsslConfig.h_ files. After applying the configuration, these files can be further adapted per specific needs and the MatrixSSL can be compiled as usual, via the make commands described in the _MatrixSSL Getting Started_ document. #5 SSL HANDSHAKING The core of SSL security is the handshake protocol that allows two peers to authenticate and negotiate symmetric encryption keys. A handshake is defined by the specific sequence of SSL messages that are exchanged between the client and server. A collection of messages being sent from one peer to another is called a flight. @@ -1079,7 +1076,9 @@ Servers will evaluate the FALLBACK_SCSV indication automatically as per RFC: > If TLS_FALLBACK_SCSV appears in ClientHello.cipher_suites and the highest protocol version supported by the server is higher than the version indicated in ClientHello.client_version, the server MUST respond with a fatal inappropriate_fallback alert ##6.8 OCSP -The Online Certificate Status Protocol (OCSP) is an alternative to the Certificate Revocation List (CRL) mechanism for performing certificate revocation tests on server keys. TLS integrates with OCSP in a mechanism known as _OCSP stapling_. This feature allows the client to request that the server provide a time-stamped OCSP response when presenting the X.509 certificate during the TLS handshake. The primary goal for this method is to allow resource constrained clients to perform certificate revocation tests without having to communicate with an OCSP Responder themselves. The general process is illustrated below. +The Online Certificate Status Protocol (OCSP) is an alternative to the Certificate Revocation List (CRL) mechanism for performing certificate revocation tests on server keys. TLS integrates with OCSP in a mechanism known as _OCSP stapling_. This feature allows the client to request that the server provide a time-stamped OCSP response when presenting the X.509 certificate during the TLS handshake. The primary goal for this method is to allow resource constrained clients to perform certificate revocation tests without having to communicate with an OCSP Responder themselves. The general process is illustrated below. The MatrixSSL also +supports OCSP request generation, to do revocation tests on certificates without +TLS server supporting OCSP stapling. OCSP stapling is specified in Section 8 (Certificate Status Request) of the TLS Extensions [RFC 6066](https://tools.ietf.org/html/rfc6066#section-8). The `USE_OCSP` define in cryptoConfig.h must be enabled for these features to be available. @@ -1114,6 +1113,184 @@ A server application wishing to support OCSP stapling must communicate out of ba When a client sends the `status_request` extension the server will look to see if an OCSP response is available in the `sslKeys_t` structure and reply with a `status_request` extension and the `CERTIFICATE_STATUS` message that holds the OCSP response for the client to validate. +### Configuring OCSP Feature for Use + +The OCSP functionality depends on definitions in `cryptoConfig.h`. Full read/write functionality and server features requires following defines: +``` {.c} +#define USE_X509 +#define USE_CERT_PARSE +#define USE_FULL_CERT_PARSE +#define USE_CRL +#define USE_OCSP +#define USE_OCSP_MUST_STAPLE +``` + +The standard configurations like `default` on *MatrixSSL* FIPS and Commercial releases have already neccessary features enabled. + +### Invoking OCSP Manually + +#### OCSP Example Application + +OCSP use has example application `ocsp.c` in `apps/crypto` subdirectory of *MatrixSSL*. The compiled application will be known as `matrixOCSP`. +This application can be used to create OCSP requests and get responses. The easiest way to study OCSP functionality is to use and examine this application. The application provides usage instructions when invoked without parameters. Some of most interesting options include `-request`and `-reply` which allow storing requests and responses for examination with various other tools supporting OCSP and/or ASN.1 DER/BER. +The most MatrixSSL supported functions are used by this program. + +The most of functionality of `ocsp.c` program is found in `OCSPRequestAndResponseTest()` function, and this function is most useful to study for creating OCSP requests and validating OCSP responses. + +#### Creating OCSP request data + +In MatrixSSL, function `matrixSslWriteOCSPRequestExt()` is used to create OCSP requests. + +The function is invoked as follows: +``` {.c} +if (matrixSslWriteOCSPRequestExt(NULL, + subject, + issuer, + &request, + &requestLen, + &info) != PS_SUCCESS) { + /* Error handling */ + return PS_FAILURE; +} +``` + +The memory pool is usually passed in as NULL. The certificates `subject` (certificate to check) and `issuer` (for issuer of certificate to check needs to be provided). New memory will be allocated for request and the pointer of request will be written to `request`, and the amount of memory allocated will be written to `requestLen`. + +`info` is used to provide options for OCSP request. These options are discussed below. The memory allocated for OCSP request shall be freed after the request +is no longer needed. + +##### Providing Nonce Extension + +The *MatrixSSL* provides nonce for OCSP nonce extension via `info.flags` flag `MATRIXSSL_WRITE_OCSP_REQUEST_FLAG_NONCE`. The OCSP nonce extension provide unique nonce value, which can be used to the request is replied with a new (rather than cached) OCSP response. + +##### Providing name for requestor (requestorName) + +The MatrixSSL allows providing name for OCSP requestor. The name is represented +using X.509 GeneralName. matrixSslWriteOCSPRequestInfoSetRequestorId() function +is provided to help encoding the OCSP requestor name in suitable format for +OCSP request. Note: This option is relatively rarely used and some OCSP +Responders will reject requests with RequestorName. + +##### Providing list of requests (requestList) + +If `matrixSslWriteOCSPRequestInfo_t` flag `MATRIXSSL_WRITE_OCSP_REQUEST_FLAG_CERT_LIST` is specified, +then OCSP request is made concerning a list of certificates linked +(via `subject->next`). This is a convenient way to allow for less network +traffic when working with the certificates from the same issuer. +Note: Some OCSP responders only support single request, and will reject requests +concerning multiple certificates. + +#### Interacting with OCSP server + +The most OCSP servers use **HTTP** protocol. The *MatrixSSL* provides `psUrlInteract()` function, to create HTTP request and get HTTP response. When OCSP is used in SSL/TLS context, the most commonly `subject` certificate will contain AuthorityInfoAccess information regarding what server will provide OCSP information. It is accessed via `authorityInfoAccess` field of the Certificate structure `psX509Cert_t`. + +You can see `getOCSPResponse()` function in `ocsp.c` for a concrete example on how to interact with the server. + +To use HTTP protocol, it is necessary to know the correct URL. The URL is in practice commonly specified in AuthorityInfoAccess extensions of X.509 certificate. The following function will extract authority information from X.509 certificate. +```{.c} +static char *getAuthorityInfoOCSP_URI(const psX509Cert_t *subject) +{ + char *url = NULL; + x509authorityInfoAccess_t *authInfo; + authInfo = subject->extensions.authorityInfoAccess; + + /* Find the first AuthorityInfoAccess extension data with + OCSP information. */ + while(authInfo != NULL) { + if (authInfo->ocsp && authInfo->ocspLen > 0) { + url = calloc(1, authInfo->ocspLen + 1); + if (url) { + memcpy(url, authInfo->ocsp, authInfo->ocspLen); + } + break; + } + authInfo = authInfo->next; + } + return url; +} +``` + +The interaction will result in getting an HTTP error code or OCSP response. The OCSP response can be analyzed and verified using the functions described in the next chapter. + +#### Working with OCSP response + +Working with OCSP response actually consists of four phases: + +- Obtaining and checking issuer certificate +- Parsing +- Checking of time-stamps +- Validation of response + +The functions support both OCSP responses just retrieved as response to a constructed OCSP request and cached OCSP requests. One type of cache OCSP response often used in SSL/TLS is the ones used in OCSP stapling. + +#### Obtaining and checking issuer certificate + +To validate OCSP response, an issuer certificate is used. Many organizations use the same certificates to sign OCSP responses than are used to validate certificates themselves. In this case, the issuer certificate has been obtained and validated already as part of X.509 certificate validation. In case, OCSP responses have been signed with other keys designated for that purpose, then they shall be validated just like any other X.509 intermediate certificate, e.g. using `psX509ParseCert()` and `psX509AuthenticateCert()`. + +The certificate of keys intended to be used for OCSP may have been marked for that purpose. This can be checked e.g. with the following code: +```{.c} +bool gotEKU_OCSP = false; +bool gotKU_OCSP = false; +const x509v3extensions_t *ext = &issuer->extensions; +/* Specific flag for OCSP. */ +if ((ext->ekuFlags & EXT_KEY_USAGE_OCSP_SIGNING) > 0) + gotEKU_OCSP = true; +/* No OCSP specific flag, use generic digital signatures flag. */ +if ((ext->keyUsageFlags & KEY_USAGE_DIGITAL_SIGNATURE) > 0) + gotKY_OCSP = true; +``` +Only if both key usage and extended key usage flags are found in the certificate, the key can be considered to be marked for OCSP usage. However, many of the keys used for OCSP do not have this purpose marked in their certificate, and the most important validity check for OCSP signers remains ensuring that they have been signed by (one of) the CA root(s). + +#### Parsing OCSP response + +OCSP response can be parsed using function `parseOCSPResponse()`. Parsing does not validate the response for correctness, but translates the response to internal form (`mOCSPResponse_t`), which allows easier working with the response. + +#### Checking time-stamps + +The times in OCSP response are validated with `checkOCSPResponseDates()` function. The function will check the times in the OCSP response with respect to the current time and provide `struct tm` field representing various times (*ProducedAt*, *thisUpdate*, *nextUpdate*) within OCSP response. If OCSP response has timed out the function will return `PS_TIMEOUT_FAIL`. + +The time validation function allows some clock skew between server and client. The default value is provided by `PS_OCSP_TIME_LINGER`, it is two minutes. It is possible to provide different values depending on how well the clocks are expected to be synchronized. + +If OCSP response is found to be no longer valid or there is another issue in timestamps, then the application should not accept the OCSP response or process it further. + +#### Validating OCSP response + +The purpose of OCSP is to check if a certificate is revoked. `validateOCSPResponse_ex()` function is (finally) provided for this purpose. The function supports many different arguments. The options are used to pass in optional arguments. + +``` {.c} +opts.knownFlag = &known; +opts.revocationFlag = &revocated; +opts.nonceMatch = &nonceOk; +opts.revocationTime = &revocationTime; +opts.revocationReason = &revocationReason; +opts.request = request; +opts.requestLen = requestLen; +if (validateOCSPResponse_ex(NULL, + issuer, + subject, + &response, + &opts) != PS_SUCCESS) { + /* Error handling */ + return PS_FAILURE; +} +``` + +The memory pool is usually passed in as NULL. The certificates `subject` (certificate to check) and `issuer` (for expected issuer of certificate needs to be provided). `response` is the response to work with. This function returns *PS_SUCCESS* only when validation has been deemed success, and the certificate has not been found to be revoked. + +In the simplest usage of this function, only the return code is checked. The *PS_SUCCESS* return code is only gotten if certificate is **not revoked** and the response has been successfully validated. + +`opts` is used to provide options for OCSP response parsing. These options will provide more information regarding successful and unsuccessful invocation of `validateOCSPResponse_ex()`. The options are discussed below. + +##### Revocation status and reason +Flag pointed by `opts.knownFlag` will be set to *true* (1) if OCSP response contained information regarding this certificate (`subject`). Responses not containing information regarding the certificate should be dismissed. +If certificate has been revoked, flag pointed by `opts.revocationFlag` will be set to *true* (1). If available, variables pointed by `opts.revocationReason` and `opts.revocationTime` and will be set to indicate the revocation reason and time respectively. In OCSP protocol, revocation reasons are indicated by numbers between 1 and 10, the same codes used by CRL. (See function `mapRevocationReason()` in `ocsp.c` for mapping the numbers to various reasons). + +##### Nonce validation + +For validating OCSP nonce, it is necessary to provide the OCSP request as pointer and length pair to `validateOCSPResponse_ex()` function, using `opts.request` and `opts.requestLen`. If the same nonce is found in OCSP request and response, that is considered a match and flag pointed to by `opts.nonceMatch` is set to *true* (1). + +Currently, OCSP nonce is not supported by many of the OCSP servers deployed in practice, and therefore, it is recommended to not rely on OCSP nonce feature to be provided by third party OCSP servers. + ##6.9 MatrixSSL Statistics Framework Implementations that wish to capture counts of SSL events can tap into the `MATRIXSSL_STATS` framework by enabling `USE_MATRIXSSL_STATS` during the compile. The mechanism is a very simple callback that can be registered to record whatever specific SSL event the user wants. The default set of events capture the following: diff --git a/matrixssl/Makefile b/matrixssl/Makefile index ddc67a4..13566c8 100644 --- a/matrixssl/Makefile +++ b/matrixssl/Makefile @@ -42,3 +42,6 @@ $(STATIC): $(OBJS) clean: rm -f $(STATIC) $(OBJS) +# Allows to check configuration options. +parse-config: + echo '#include "matrixsslConfig.h"' | $(CC) $(CFLAGS) -dM -E -x c - diff --git a/matrixssl/dtls.c b/matrixssl/dtls.c index edb0bfc..32df074 100644 --- a/matrixssl/dtls.c +++ b/matrixssl/dtls.c @@ -196,7 +196,7 @@ int32 dtlsWriteCertificate(ssl_t *ssl, int32 certLen, int32 lsize, } -#if defined(USE_SERVER_SIDE_SSL) || defined(USE_CLIENT_AUTH) +#if defined(USE_SERVER_SIDE_SSL) && defined(USE_CLIENT_AUTH) /******************************************************************************/ /* The certificate_request message spans records @@ -314,7 +314,9 @@ int32 dtlsWriteCertificateRequest(psPool_t *pool, ssl_t *ssl, int32 certLen, psFree(tmpStart, pool); return wLen; } +#endif /* USE_SERVER_SIDE_SSL && USE_CLIENT_AUTH */ +#if defined(USE_SERVER_SIDE_SSL) || defined(USE_CLIENT_AUTH) /******************************************************************************/ /* Given the data message and lengths, chunk up the message into a diff --git a/matrixssl/hsDecode.c b/matrixssl/hsDecode.c index cf9869b..6feebb5 100644 --- a/matrixssl/hsDecode.c +++ b/matrixssl/hsDecode.c @@ -81,7 +81,11 @@ int32 parseClientHello(ssl_t *ssl, unsigned char **cp, unsigned char *end) #ifndef USE_SSL_PROTOCOL_VERSIONS_OTHER_THAN_3 /* RFC 5246 Suggests to accept all RSA minor versions, but only major version 0x03 (SSLv3, TLS 1.0, TLS 1.1, TLS 1.2, TLS 1.3 etc) */ - if (ssl->reqMajVer != 0x03 && ssl->reqMajVer != DTLS_MAJ_VER) { + if (ssl->reqMajVer != 0x03 +#ifdef USE_DTLS + && ssl->reqMajVer != DTLS_MAJ_VER +#endif /* USE_DTLS */ + ) { /* Consider invalid major version protocol version error. */ ssl->err = SSL_ALERT_PROTOCOL_VERSION; psTraceInfo("Won't support client's SSL major version\n"); diff --git a/matrixssl/matrixssl.c b/matrixssl/matrixssl.c index 6d045c8..71acda1 100644 --- a/matrixssl/matrixssl.c +++ b/matrixssl/matrixssl.c @@ -301,7 +301,9 @@ int32 curveIdToFlag(int32 id) static int32 testUserEc(int32 ecFlags, const sslKeys_t *keys) { const psEccKey_t *eccKey; +#ifdef USE_CERT_PARSE psX509Cert_t *cert; +#endif /* USE_CERT_PARSE */ #if defined(USE_SERVER_SIDE_SSL) || defined(USE_CLIENT_AUTH) if (keys->privKey.type == PS_ECC) { @@ -311,6 +313,7 @@ static int32 testUserEc(int32 ecFlags, const sslKeys_t *keys) } } +#ifdef USE_CERT_PARSE cert = keys->cert; while (cert) { if (cert->publicKey.type == PS_ECC) { @@ -321,7 +324,8 @@ static int32 testUserEc(int32 ecFlags, const sslKeys_t *keys) } cert = cert->next; } -#endif +#endif /* USE_CERT_PARSE */ +#endif /* USE_SERVER_SIDE_SSL || USE_CLIENT_AUTH */ #if defined(USE_CLIENT_SIDE_SSL) || defined(USE_CLIENT_AUTH) cert = keys->CAcerts; @@ -334,7 +338,7 @@ static int32 testUserEc(int32 ecFlags, const sslKeys_t *keys) } cert = cert->next; } -#endif +#endif /* USE_CLIENT_SIDE_SSL || USE_CLIENT_AUTH */ return PS_SUCCESS; } @@ -344,6 +348,7 @@ static int32 testUserEc(int32 ecFlags, const sslKeys_t *keys) #ifdef MATRIX_USE_FILE_SYSTEM #ifdef USE_PKCS12 +#ifdef USE_CERT_PARSE /* Have seen cases where the PKCS#12 files are not in a child-to-parent order */ static void ReorderCertChain(psX509Cert_t *a_cert) { @@ -369,6 +374,7 @@ static void ReorderCertChain(psX509Cert_t *a_cert) currCert = currCert->next; } } +#endif /* USE_CERT_PARSE */ /******************************************************************************/ /* @@ -404,7 +410,9 @@ int32 matrixSslLoadPkcs12(sslKeys_t *keys, const unsigned char *certFile, psClearPubKey(&keys->privKey); return rc; } +#ifdef USE_CERT_PARSE ReorderCertChain(keys->cert); +#endif /* USE_CERT_PARSE */ #if defined(USE_SERVER_SIDE_SSL) || defined(USE_CLIENT_AUTH) if (verifyReadKeys(pool, keys, keys->poolUserPtr) < PS_SUCCESS) { psTraceInfo("PKCS#12 parse success but material didn't validate\n"); @@ -480,14 +488,16 @@ static int32 matrixSslLoadKeyMaterial(sslKeys_t *keys, const char *certFile, &keys->cert, flags)) < 0) { return err; } +#ifdef USE_CERT_PARSE if (keys->cert->authFailFlags) { psAssert(keys->cert->authFailFlags == PS_CERT_AUTH_FAIL_DATE_FLAG); #ifdef POSIX /* TODO - implement date check on WIN32, etc. */ psX509FreeCert(keys->cert); keys->cert = NULL; return PS_CERT_AUTH_FAIL_EXTENSION; -#endif +#endif /* POSIX */ } +#endif /* USE_CERT_PARSE */ #else psTraceStrInfo("Ignoring %s certFile in matrixSslReadKeys\n", (char *)certFile); @@ -637,7 +647,7 @@ int32_t matrixSslGenEphemeralEcKey(sslKeys_t *keys, psEccKey_t *ecc, psAssert(keys && curve); #if ECC_EPHEMERAL_CACHE_USAGE > 0 psGetTime(&t, keys->poolUserPtr); - (void)psLockMutex(&keys->cache.lock); + psLockMutex(&keys->cache.lock); if (keys->cache.eccPrivKey.curve != curve) { psTraceStrInfo("Generating ephemeral %s key (new curve)\n", curve->name); @@ -659,7 +669,7 @@ int32_t matrixSslGenEphemeralEcKey(sslKeys_t *keys, psEccKey_t *ecc, if (ecc) { rc = psEccCopyKey(ecc, &keys->cache.eccPrivKey); } - (void)psUnlockMutex(&keys->cache.lock); + psUnlockMutex(&keys->cache.lock); return rc; L_REGEN: if (keys->cache.eccPrivKeyUse) { @@ -669,7 +679,7 @@ L_REGEN: } rc = psEccGenKey(keys->pool, &keys->cache.eccPrivKey, curve, hwCtx); if (rc < 0) { - (void)psUnlockMutex(&keys->cache.lock); + psUnlockMutex(&keys->cache.lock); return rc; } keys->cache.eccPrivKeyTime = t; @@ -678,7 +688,7 @@ L_REGEN: if (ecc) { rc = psEccCopyKey(ecc, &keys->cache.eccPrivKey); } - (void)psUnlockMutex(&keys->cache.lock); + psUnlockMutex(&keys->cache.lock); return rc; #else /* Not using ephemeral caching. */ @@ -2379,14 +2389,15 @@ ERR_LOCKED: /******************************************************************************/ /* - @note careful, this function assumes the lock is on so must relock before - leaving if SUCCESS case. Failure assumes it's unlocked + @pre Must be called with g_sessTicketLock locked. Returns in all cases + with g_sessTicketLock locked. */ static int32 getTicketKeys(ssl_t *ssl, unsigned char *c, psSessionTicketKeys_t **keys) { psSessionTicketKeys_t *lkey; unsigned char name[16]; + int32_t rc; short cachedTicket = 0; /* First 16 bytes are the key name */ @@ -2398,7 +2409,7 @@ static int32 getTicketKeys(ssl_t *ssl, unsigned char *c, if (memcmp(lkey->name, name, 16) == 0) { lkey->inUse = 1; *keys = lkey; - /* Have the key. Invoke callback with SUCCESS */ + /* Have the key. Invoke callback with SUCCESS */ if (ssl->keys->ticket_cb) { cachedTicket++; break; @@ -2412,40 +2423,33 @@ static int32 getTicketKeys(ssl_t *ssl, unsigned char *c, if (ssl->keys->ticket_cb) { /* Unlock. Cback will likely call matrixSslLoadSessionTicketKeys */ psUnlockMutex(&g_sessTicketLock); - if (ssl->keys->ticket_cb((struct sslKeys_t*)ssl->keys, name, - cachedTicket) < 0) { + rc = ssl->keys->ticket_cb((struct sslKeys_t*)ssl->keys, name, cachedTicket); + psLockMutex(&g_sessTicketLock); + if (rc < 0) { if (lkey) { /* inUse could be set in the odd case where we found the cached key but the user didn't want to use it. */ lkey->inUse = 0; } return PS_FAILURE; /* user couldn't find it either */ - } else { - /* found it */ - psLockMutex(&g_sessTicketLock); - if (cachedTicket == 0) { - /* it's been found and added at end of list. confirm this */ - lkey = ssl->keys->sessTickets; - if (lkey == NULL) { - psUnlockMutex(&g_sessTicketLock); - return PS_FAILURE; /* user claims they added, but empty */ - } - while (lkey->next) { - lkey = lkey->next; - } - if (memcmp(lkey->name, c, 16) != 0) { - psUnlockMutex(&g_sessTicketLock); - return PS_FAILURE; /* user claims to have added, but... */ - } - lkey->inUse = 1; - *keys = lkey; + } + /* found it */ + if (cachedTicket == 0) { + /* it's been found and added at end of list. confirm this */ + lkey = ssl->keys->sessTickets; + if (lkey == NULL) { + return PS_FAILURE; /* user claims they added, but empty */ } - return PS_SUCCESS; + while (lkey->next) { + lkey = lkey->next; + } + if (memcmp(lkey->name, c, 16) != 0) { + return PS_FAILURE; /* user claims to have added, but... */ + } + lkey->inUse = 1; + *keys = lkey; } - } else { - /* Unlock, because if the function fails, the - locking status need to be unlocked. */ - psUnlockMutex(&g_sessTicketLock); + return PS_SUCCESS; } return PS_FAILURE; /* not in list and no callback registered */ } @@ -2478,8 +2482,8 @@ int32 matrixUnlockSessionTicket(ssl_t *ssl, unsigned char *in, int32 inLen) len = inLen; psLockMutex(&g_sessTicketLock); if (getTicketKeys(ssl, c, &keys) < 0) { + psUnlockMutex(&g_sessTicketLock); psTraceInfo("No key found for session ticket\n"); - /* We've been unlocked in getTicketKeys */ return PS_FAILURE; } @@ -2758,9 +2762,7 @@ void sslResetContext(ssl_t *ssl) ssl->bFlags = 0; /* Reset buffer control */ } -#ifndef USE_ONLY_PSK_CIPHER_SUITE -#if defined(USE_CLIENT_SIDE_SSL) || defined(USE_CLIENT_AUTH) - +#ifdef USE_CERT_VALIDATE static int wildcardMatch(char *wild, char *s) { char *c, *e; @@ -2946,7 +2948,6 @@ int32 matrixValidateCerts(psPool_t *pool, psX509Cert_t *subjectCerts, */ return PS_CERT_AUTH_FAIL; } -#endif /* USE_CLIENT_SIDE_SSL || USE_CLIENT_AUTH */ /******************************************************************************/ /* @@ -2991,7 +2992,7 @@ int32 matrixUserCertValidator(ssl_t *ssl, int32 alert, */ return certValidator(ssl, subjectCert, status); } -#endif /* !USE_ONLY_PSK_CIPHER_SUITE */ +#endif /* USE_CERT_VALIDATE */ /******************************************************************************/ #ifdef USE_MATRIXSSL_STATS diff --git a/matrixssl/matrixsslCheck.h b/matrixssl/matrixsslCheck.h index b8eb8dd..a4651cf 100644 --- a/matrixssl/matrixsslCheck.h +++ b/matrixssl/matrixsslCheck.h @@ -97,12 +97,12 @@ extern "C" { /* SHA1 and MD5 are essential elements for SSL key derivation during protocol */ -#if !defined USE_MD5 || !defined USE_SHA1 +#ifndef USE_MD5SHA1 #if defined(USE_TLS_1_2) && defined(DISABLE_TLS_1_0) && defined(DISABLE_TLS_1_1) \ && defined(DISABLE_SSLV3) #define USE_ONLY_TLS_1_2 #else - #error "Must enable both USE_MD5 and USE_SHA1 in cryptoConfig.h for < TLS 1.2" + #error "Must enable USE_MD5SHA1 in cryptoConfig.h for < TLS 1.2" #endif #endif @@ -1116,6 +1116,12 @@ typedef int32 psX509Cert_t; #endif #endif +#if defined(USE_CLIENT_AUTH) || defined(USE_CLIENT_SIDE_SSL) +#if defined(USE_CERT_PARSE) && !defined(USE_ONLY_PSK_CIPHER_SUITE) +#define USE_CERT_VALIDATE /* Shorthand. */ +#endif /* USE_CERT_PARSE && USE_ONLY_PSK_CIPHER_SUITE */ +#endif /* USE_CLIENT_AUTH || USE_CLIENT_SIDE_SSL */ + #ifdef USE_TRUSTED_CA_INDICATION #ifndef ENABLE_CA_CERT_HASH #error "Define ENABLE_CA_CERT_HASH in cryptoConfig.h for Trusted CA Indication" diff --git a/matrixssl/sslDecode.c b/matrixssl/sslDecode.c index 8234790..8bd5e57 100644 --- a/matrixssl/sslDecode.c +++ b/matrixssl/sslDecode.c @@ -1809,8 +1809,7 @@ parseHandshake: psTraceInfo("Expecting CERTIFICATE_STATUS message\n"); ssl->err = SSL_ALERT_UNEXPECTED_MESSAGE; return MATRIXSSL_ERROR; -#endif - +#else #ifdef USE_DHE_CIPHER_SUITE if (ssl->flags & SSL_FLAGS_DHE_KEY_EXCH && hsType == SSL_HS_SERVER_KEY_EXCHANGE) { @@ -1822,6 +1821,7 @@ parseHandshake: ssl->hsState = hsType; goto hsStateDetermined; } +#endif /* USE_OCSP_MUST_STAPLE */ } #endif /* USE_OCSP */ diff --git a/matrixssl/sslEncode.c b/matrixssl/sslEncode.c index 6b698bb..0bf4af1 100644 --- a/matrixssl/sslEncode.c +++ b/matrixssl/sslEncode.c @@ -295,6 +295,8 @@ static int32 addCertFragOverhead(ssl_t *ssl, int32 totalCertLen) #endif /* ! ONLY_PSK */ #ifdef USE_ECC +#if defined(USE_SERVER_SIDE_SSL) || defined(USE_CLIENT_AUTH) +#ifndef USE_ONLY_PSK_CIPHER_SUITE /* ECDSA signature is two DER INTEGER values. Either integer could result in the high bit being set which is interpreted as a negative number unless proceeded by a 0x0 byte. MatrixSSL predicts one of the two will @@ -469,9 +471,10 @@ static int accountForEcdsaSizeChange(ssl_t *ssl, pkaAfter_t *pka, int real, } return PS_SUCCESS; } +#endif /* !USE_ONLY_PSK_CIPHER_SUITE */ +#endif /* USE_SERVER_SIDE_SSL || USE_CLIENT_AUTH */ #endif /* USE_ECC */ - #ifdef USE_SERVER_SIDE_SSL /* The ServerKeyExchange delayed PKA op */ static int32 nowDoSkePka(ssl_t *ssl, psBuf_t *out) @@ -2184,7 +2187,8 @@ static int32 encryptFlight(ssl_t *ssl, unsigned char **end) /* NEGATIVE ECDSA - save the end of the flight buffer */ origEnd = *end; - + PS_VARIABLE_SET_BUT_UNUSED(origEnd); + msg = ssl->flightEncode; while (msg) { c = msg->start + msg->len; @@ -6492,12 +6496,14 @@ static int32 writeCertificateRequest(ssl_t *ssl, sslBuf_t *out, int32 certLen, Is this the fragment case? */ if (rc == DTLS_MUST_FRAG) { +#ifdef USE_CLIENT_AUTH rc = dtlsWriteCertificateRequest(ssl->hsPool, ssl, certLen, certCount, sigHashLen, c); if (rc < 0) { return rc; } c += rc; +#endif /* USE_CLIENT_AUTH */ out->end = c; return MATRIXSSL_SUCCESS; } diff --git a/matrixssl/test/certValidate.c b/matrixssl/test/certValidate.c index bdd1461..b8dbf95 100644 --- a/matrixssl/test/certValidate.c +++ b/matrixssl/test/certValidate.c @@ -36,7 +36,7 @@ /****************************** Local Functions *******************************/ -#if ((!defined USE_ONLY_PSK_CIPHER_SUITE) && (defined MATRIX_USE_FILE_SYSTEM)) +#if defined(USE_CERT_VALIDATE) && defined(MATRIX_USE_FILE_SYSTEM) static void usage(void) { @@ -237,11 +237,23 @@ L_EXIT: int32 main(int32 argc, char **argv) { +#ifndef USE_CERT_PARSE + printf("Please enable USE_CERT_PARSE for this test\n"); +#endif +#ifndef USE_MATRIX_FILE_SYSTEM + printf("Please enable USE_MATRIX_FILE_SYSTEM for this test\n"); +#endif +#ifdef USE_ONLY_PSK_CIPHER_SUITE printf("Not applicable when USE_ONLY_PSK_CIPHER_SUITE defined\n"); +#endif +#if !defined(USE_CLIENT_SIDE_SSL) && !defined(USE_CLIENT_AUTH) + printf("Certificate validation requires either USE_CLIENT_SIDE_SSL " \ + "or USE_CLIENT_AUTH. Please enable one of those\n"); +#endif return 0; } -#endif /* USE_ONLY_PSK_CIPHER_SUITE */ +#endif /* USE_CERT_VALIDATE && MATRIX_USE_FILE_SYSTEM */ /******************************************************************************/ diff --git a/matrixssl/test/sslTest.c b/matrixssl/test/sslTest.c index b407205..5734ae8 100644 --- a/matrixssl/test/sslTest.c +++ b/matrixssl/test/sslTest.c @@ -110,7 +110,15 @@ static void statCback(void *ssl, void *stat_ptr, int32 type, int32 value); */ #if !defined(USE_SERVER_SIDE_SSL) || !defined(USE_CLIENT_SIDE_SSL) #warning "Must enable both USE_SERVER_SIDE_SSL and USE_CLIENT_SIDE_SSL to run" -#endif + +#include +int main(void) +{ + printf("Must enable both USE_SERVER_SIDE_SSL and USE_CLIENT_SIDE_SSL to run\n"); + return 1; +} + +#else #ifdef USE_ONLY_PSK_CIPHER_SUITE #ifdef USE_CLIENT_AUTH @@ -2253,3 +2261,4 @@ static void statCback(void *ssl, void *stat_ptr, int32 type, int32 value) #endif /******************************************************************************/ +#endif /* !defined(USE_SERVER_SIDE_SSL) || !defined(USE_CLIENT_SIDE_SSL) */ diff --git a/matrixssl/version.h b/matrixssl/version.h index 4592687..1515dfa 100644 --- a/matrixssl/version.h +++ b/matrixssl/version.h @@ -8,10 +8,10 @@ extern "C" { #endif -#define MATRIXSSL_VERSION "3.8.6-OPEN" +#define MATRIXSSL_VERSION "3.8.7-OPEN" #define MATRIXSSL_VERSION_MAJOR 3 #define MATRIXSSL_VERSION_MINOR 8 -#define MATRIXSSL_VERSION_PATCH 6 +#define MATRIXSSL_VERSION_PATCH 7 #define MATRIXSSL_VERSION_CODE "OPEN" #ifdef __cplusplus