diff --git a/CHANGES.md b/CHANGES.md index 75de4a8..ce231f5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,67 @@ MatrixSSL Release Notes ======== +#Changes in 3.8.4 +-------- +> **Version 3.8.4** +> July 2016 +> *© INSIDE Secure - 2016 - All Rights Reserved* + +1. FEATURES AND IMPROVEMENTS + - Coverity coverage + - HTTP/2 restrictions via ALPN + - Enhanced example apps + - Process shared Session Cache + - Enhanced CRL and OCSP support + - Windows support for certificate date validation +2. BUG FIXES + - Critical parsing bug for RSA encrypted blobs + - Additional restrictions on bignum operations + - Fixed error in disabled cipher flags + - Fixed error in DTLS encoding + - SSLv3 only support fixed + - Assembly compatibility with more compilers + +#1 FEATURES AND IMPROVEMENTS + +##Coverity coverage +MatrixSSL now has zero outstanding defects in [Coverity Static Analysis](https://scan.coverity.com/projects/matrixssl-matrixssl). + +##HTTP/2 restrictions via ALPN +MatrixSSL server code will automatically evaluate the ALPN extension and appropriately restrict the cipher suites and key exchange methods if the HTTP/2 protocol is being used. Per the [HTTP/2 spec](https://tools.ietf.org/html/rfc7540#appendix-A), only AEAD cipher suites and Ephemeral key exchange methods are allowed. + +##Enhanced example apps +Example applications now take additional command line options and also support CRL request and response generation. + +##Process shared Session Cache +Minimal support for a process-shared server session resumption cache is now supported via process-shared mutexes on Linux. + +##Enhanced CRL and OCSP support +A new file _crypto/keyformat/crl.c_ defines additional apis for more complex CRL (Certificate Revocation List) and OCSP support. + +##Windows support for certificate date validation +Previously only Posix based platforms were supported. + +#2 BUG FIXES + +##Critical parsing bug for RSA encrypted blobs +Security Researcher [Hanno Böck](https://hboeck.de/) reported several issues related to RSA and bignum operations. An error in parsing a maliciously formatted public key block could produce a remotely triggered crash in SSL server parsing. Additional restrictions on the values provided to RSA and DH operations were also added, although an exploit has not been found. + +##Additional restrictions on bignum operations +The MatrixSSL bignum library, located in _crypto/math/_ was optimized and reduced in size to support only key sizes and operations used by standard RSA, ECC and DH operations (those apis present in _crypto/cryptoApi.h_). Additional constraint checking has been added to the code to prevent unsupported key sizes and values. Users requiring generic bignum operations should take a look at libtomcrypt, GMP, Python or OpenSSL. + +##Fixed error in disabled cipher flags +The optional disabling or enabling of specific ciphers at runtime per session was recently broken (now fixed) due to an errant flags calculation using `<` instead of `<<`. + +##Fixed error in DTLS encoding +An error was returned if attempting to encode a DTLS message exactly the PMTU size. + +##SSLv3 only support fixed +SSLv3 mode is not recommended for deployment, but had become broken in a recent build. It can now be enabled again. + +## Assembly compatibility with more compilers +Fixed "invalid register constraints" error on some versions of GCC and LLVM for ARM, MIPS and x86_64. + #Changes in 3.8.3 -------- > **Version 3.8.3** diff --git a/FILES b/FILES index 1a61137..a48b0bd 100644 --- a/FILES +++ b/FILES @@ -5,6 +5,14 @@ Makefile Top level Makefile. Builds core, crypto, matrixssl and apps common.mk Top level file for common make definitions. +pgp.asc + Public GPG key for MatrixSSL code signatures and vulnerability reporting +INSTALL + Compile and run instructions +LICENSE + GPLv2 License +CHANGES.md + Changelog for latest packaged version matrixssl/ This directory contains files the implement the SSL and TLS protocol. @@ -19,7 +27,7 @@ crypto/ symmetric/ Symmetric ciphers (AES-GCM, etc.) keyformat/ - Decode/encode Certificates and keys (X.509, .pem, etc.) + Decode/encode Certificates, keys, CRL (X.509, .pem, etc.) pubkey/ RSA, ECC and DH operations math/ diff --git a/Makefile b/Makefile index 7911caa..e7f4167 100644 --- a/Makefile +++ b/Makefile @@ -18,12 +18,12 @@ libs: $(MAKE) --directory=crypto $(MAKE) --directory=matrixssl -tests: +tests: libs $(MAKE) --directory=crypto/test $(MAKE) --directory=matrixssl/test # Note apps is also a direct subdirectory -apps: +apps: libs $(MAKE) --directory=apps/ssl $(MAKE) --directory=apps/dtls diff --git a/apps/dtls/dtlsClient.c b/apps/dtls/dtlsClient.c index 2e8a921..c71349a 100644 --- a/apps/dtls/dtlsClient.c +++ b/apps/dtls/dtlsClient.c @@ -1092,7 +1092,7 @@ static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert) int32 main(int32 argc, char **argv) { printf("USE_DTLS and USE_CLIENT_SIDE_SSL must be enabled in " \ - "matrixsslConfig.h at build time to run this application\n"); + "matrixsslConfig.h at build time to run this application\n"); return -1; } #endif /* USE_DTLS && USE_CLIENT_SIDE_SSL */ diff --git a/apps/dtls/dtlsServer.c b/apps/dtls/dtlsServer.c index 5f39788..8155855 100644 --- a/apps/dtls/dtlsServer.c +++ b/apps/dtls/dtlsServer.c @@ -1270,6 +1270,7 @@ static void closeClientList() } #else + /******************************************************************************/ /* Stub main for compiling without dtls enabled diff --git a/apps/ssl/client.c b/apps/ssl/client.c index def3232..030b792 100644 --- a/apps/ssl/client.c +++ b/apps/ssl/client.c @@ -234,9 +234,30 @@ static int32_t extensionCb(ssl_t *ssl, uint16_t extType, uint8_t extLen, void *e); #ifdef USE_CRL -static int32 crlCb(psPool_t *pool, psX509Cert_t *CA, int append, - char *url, uint32 urlLen); +static int32 fetchCRL(psPool_t *pool, char *url, uint32_t urlLen, + unsigned char **crlBuf, uint32_t *crlBufLen); +static int32_t fetchParseAndAuthCRLfromCert(psPool_t *pool, psX509Cert_t *cert, + psX509Cert_t *potentialIssuers); + +/* Enable the example on how to fetch CRLs mid-handshake. If disabled, the + example will show how to halt the handshake to go out and fetch and retry + the connection (command line option -n must be specified for multiple + connection attempts) */ +//#define MIDHANDSHAKE_CRL_FETCH + +#ifndef MIDHANDSHAKE_CRL_FETCH +/* In the example where we stop the handhsake to go fetch the CRL files, we + need storage to hold the CRL URL distribution points since those are + coming from the server cert chain which we do not keep around */ +#define CRL_MAX_SERVER_CERT_CHAIN 3 +#define CRL_MAX_URL_LEN 256 +static unsigned char g_crlDistURLs[CRL_MAX_SERVER_CERT_CHAIN][CRL_MAX_URL_LEN]; + +static int32_t fetchParseAndAuthCRLfromUrl(psPool_t *pool, unsigned char *url, + uint32_t urlLen, psX509Cert_t *potentialIssuers); +static void fetchSavedCRL(psX509Cert_t *potentialIssuers); #endif +#endif /* USE_CRL */ /******************************************************************************/ @@ -750,8 +771,8 @@ static int32 process_cmd_options(int32 argc, char **argv) strcpy(g_ip, "127.0.0.1"); g_bytes_requested = 0; g_send_closure_alert = 1; - g_ciphers = 1; - g_cipher[0] = 47; + g_ciphers = 0; + g_cipher[0] = 0; g_disableCertNameChk = 0; g_key_len = 1024; g_new = 1; @@ -863,9 +884,6 @@ int32 main(int32 argc, char **argv) sslSessionId_t *sid = NULL; struct g_sslstats stats; unsigned char *CAstream; -#ifdef USE_CRL - int32 numLoaded; -#endif #ifdef WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(1, 1), &wsaData); @@ -875,7 +893,7 @@ int32 main(int32 argc, char **argv) _psTrace("MatrixSSL library init failure. Exiting\n"); return rc; } - + if (matrixSslNewKeys(&keys, NULL) < 0) { _psTrace("MatrixSSL library key init failure. Exiting\n"); return -1; @@ -1059,10 +1077,10 @@ int32 main(int32 argc, char **argv) #endif /* USE_PSK_CIPHER_SUITE */ #ifdef USE_CRL - if (matrixSslGetCRL(keys, crlCb, &numLoaded) < 0) { - _psTrace("WARNING: A CRL failed to load\n"); - } - _psTraceInt("CRLs loaded: %d\n", numLoaded); + /* One initialization step that can be taken is to run through the CA + files and see if any CRL URL distribution points are present. + Fetch the CRL and load into the cache if found */ + fetchParseAndAuthCRLfromCert(NULL, keys->CAcerts, keys->CAcerts); #endif memset(&stats, 0x0, sizeof(struct g_sslstats)); @@ -1078,6 +1096,19 @@ int32 main(int32 argc, char **argv) for (i = 0; i < g_new; i++) { matrixSslNewSessionId(&sid, NULL); +#ifdef USE_CRL +#ifndef MIDHANDSHAKE_CRL_FETCH + /* This is part of the example for an application that has chosen to + fail a handshake if the CRL was not available during the first + attempted connection. In this case, the CRL URL distribution points + have been saved aside in g_crlDistURLs and now we will go out and + fetch those CRLs and load them into the library cache so they + will be available on this next connection attempt. */ + if (g_crlDistURLs[0][0] == 'h') { /* assumption is "http" */ + fetchSavedCRL(keys->CAcerts); + } +#endif +#endif rc = httpsClientConnection(keys, sid, &stats); if (rc < 0) { printf("F %d/%d\n", i, g_new); @@ -1321,20 +1352,289 @@ static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert) _psTrace("ERROR: Problem in certificate validation. Exiting.\n"); } + +#ifdef USE_CRL + /* Examples on how to look at the CRL status for the cert chain and fetch + CRLs if they have not been loaded */ + { + psX509Crl_t *expired; +#ifdef MIDHANDSHAKE_CRL_FETCH + /* Will pause this handshake to go out and fetch a CRL via HTTP GET, + re-check for revocation and continue on if it all checks out */ + int retryOnce = 0; +RETRY_CRL_TEST_ONCE: +#else + /* Perhaps the more standard way is to stop the handshake if the CRLs have + not been fetched. Go fetch them and retry the SSL connection from + scratch. The connection reattempt will only occur if the -n command + line option has been set to something greater than 1 */ + int count = 0; + uint32_t urlLen; + unsigned char *url; +#endif + + /* Loop to look at the CRL status of each cert in the chain */ + for (next = cert; next != NULL; next = next->next) { + switch (next->revokedStatus) { + case CRL_CHECK_CRL_EXPIRED: + _psTrace("Have CRL but it is expired. Fetching new one\n"); + /* Remove the CRL from the table */ + expired = psCRL_GetCRLForCert(next); + if (expired) { + psAssert(expired->expired); + psCRL_Delete(expired); + } else { + _psTrace("Unexpected combo of expired but no CRL found\n"); + } + /* MOVING INTO CRL_CHECK_EXPECTED ON PURPOSE TO REFETCH */ + case CRL_CHECK_EXPECTED: + /* There was a CRL distribution point in this cert but we didn't + have the CRL to test against */ +#ifdef MIDHANDSHAKE_CRL_FETCH + /* It is an application choice to go out and fetch CRLs in the + middle of the handshake like this. It's probably not advised + to do this but here is an example if you'd like to do so */ + /* Only attempt this once so we don't get stuck in a loop */ + if (retryOnce) { + _psTrace("Cert was not able to be tested against a CRL\n"); + alert = SSL_ALERT_CERTIFICATE_UNKNOWN; + break; + } + _psTrace("Cert expects CRL. Mid-handshake attempt being made\n"); + /* This fetchParseAndAuthCRLfromCert will work on "next" as a chain + so it is correct that the server cert will look for the first + instance of CHECK_EXPECTED and pass that as the start of + chain to work upon */ + fetchParseAndAuthCRLfromCert(NULL, next, ssl->keys->CAcerts); + /* If all went well, every cert in the server chain will have an + updated status */ + retryOnce++; + goto RETRY_CRL_TEST_ONCE; +#else /* MIDHANSHAKE_CRL_FETCH */ + + //if (next->extensions.ak.keyId) { + // psTraceBytes("cert ak", next->extensions.ak.keyId, 20); + //} + _psTrace("Cert expects CRL. Failing handshake to go fetch it\n"); + /* A more typical case if CRL testing is expected to be done is + to halt the handshake now, go out and fetch the CRLs and + try the connection again */ + /* Not clear which alert should be associated with this + application level decision. Let's call it UNKNOWN */ + alert = SSL_ALERT_CERTIFICATE_UNKNOWN; + + /* Save aside the CRL URL distribution points to fetch after + control is given back when this handshake is done. Correct + to pick up from the current cert and work up as far as + possible */ + if (count < CRL_MAX_SERVER_CERT_CHAIN) { + memset(g_crlDistURLs[count], 0, CRL_MAX_URL_LEN); + psX509GetCRLdistURL(next, (char**)&url, &urlLen); + if (urlLen > CRL_MAX_URL_LEN) { + _psTraceInt("CLR URL distribution point longer than %d\n", + CRL_MAX_URL_LEN); + } else { + memcpy(g_crlDistURLs[count], url, urlLen); + count++; + } + } else { + _psTraceInt("Server cert chain was longer than %d\n", + CRL_MAX_SERVER_CERT_CHAIN); + } + + break; + +#endif /* MIDHANDSHAKE_CRL_FETCH */ + break; + + case CRL_CHECK_NOT_EXPECTED: + _psTrace("Cert didn't specify a CRL distribution point\n"); + break; + case CRL_CHECK_PASSED_AND_AUTHENTICATED: + _psTrace("Cert passed CRL test and CRL was authenticated\n"); + break; + case CRL_CHECK_PASSED_BUT_NOT_AUTHENTICATED: + _psTrace("Cert passed CRL test but CRL was not authenticated\n"); + break; + case CRL_CHECK_REVOKED_AND_AUTHENTICATED: + _psTrace("Cert was revoked by an authenticated CRL\n"); + alert = SSL_ALERT_CERTIFICATE_REVOKED; + break; + case CRL_CHECK_REVOKED_BUT_NOT_AUTHENTICATED: + _psTrace("Cert was revoked but the CRL wasn't authenticated\n"); + alert = SSL_ALERT_CERTIFICATE_REVOKED; + break; + default: + break; + } + } + } /* End CRL local code block */ +#endif + if (g_trace && alert == 0 && cert) { _psTraceStr("SUCCESS: Validated cert for: %s.\n", cert->subject.commonName); } #endif /* !USE_ONLY_PSK_CIPHER_SUITE */ return alert; +} /* end certificate callback */ + + +/******************************************************************************/ +#ifdef USE_CRL + +#ifndef MIDHANDSHAKE_CRL_FETCH +/* Part of example for halting handshake because no CRL was available. Now + we have closed that handshake and are fetching the CRLs that were set + aside during the certificate callback. We use our list of CA files as + potential issuers here so we can attempt a round of CRL authentications. + This authentication round will save time during the next handshake */ +static void fetchSavedCRL(psX509Cert_t *potentialIssuers) +{ + int i; + + /* Test for 'h' is assuming URL to begin with "http" */ + for (i = 0; i < CRL_MAX_SERVER_CERT_CHAIN && g_crlDistURLs[i][0] == 'h'; + i++) { + fetchParseAndAuthCRLfromUrl(NULL, g_crlDistURLs[i], + strlen((char*)g_crlDistURLs[i]), potentialIssuers); + memset(g_crlDistURLs[i], 0, CRL_MAX_URL_LEN); + } } -#ifdef USE_CRL -/* Basic example of matrixSslGetCRL callback for downloading a CRL from a given - URL and passing the CRL contents to matrixSslLoadCRL +/* Fetch a CRL give an URL. Once you have it, check to see if it can be + authenticated by any of the "potentialIssuers" + + Regardless of authentication status, add any CRL that is found + to the global cache for access inside the library during internal + authentications */ +static int32_t fetchParseAndAuthCRLfromUrl(psPool_t *pool, unsigned char *url, + uint32_t urlLen, psX509Cert_t *potentialIssuers) +{ + unsigned char *crlBuf; + uint32_t crlBufLen; + psX509Crl_t *crl; + psX509Cert_t *ic; + + /* url need not be freed. It points into cert structure */ + if (fetchCRL(NULL, (char*)url, urlLen, &crlBuf, &crlBufLen) < 0){ + _psTrace("Unable to fetch CRL\n"); + return -1; + } + /* Convert the CRL stream into our structure */ + if (psX509ParseCRL(pool, &crl, crlBuf, crlBufLen) < 0) { + _psTrace("Unable to parse CRL\n"); + psFree(crlBuf, pool); + return -1; + } + psFree(crlBuf, pool); + + /* Adding the CRL to the global cache. This local crl is now the + same memory as the entry in the global cache and is managed + there. Freeing will now be done with psCRL_DeleteAll at + application closure */ + psCRL_Update(crl, 1); /* The 1 will delete old CRLs */ + + /* Important to separate the concept of the CRL authentication + from the cert authentication. Here, we run through the + list of potential issuers the caller thinks could work */ + for (ic = potentialIssuers; ic != NULL; ic = ic->next) { + if (psX509AuthenticateCRL(ic, crl, NULL) > 0) { + _psTrace("NOTE: Able to authenticate CRL\n"); + break; /* Stop looking */ + } + } + return PS_SUCCESS; +} +#endif /* ifndef MIDHANDSHAKE_CRL_FETCH */ + +/* Take the CRL Distribution URL from the "cert" (may be a chain) and go fetch + the CRL. Once you have it, check to see if it can be authenticated by any + of the "potentialIssuers" OR by the "cert" chain itself. + + Regardless of authentication status, add any CRL that is found + to the global cache for access inside the library during internal + authentications */ +static int32_t fetchParseAndAuthCRLfromCert(psPool_t *pool, psX509Cert_t *cert, + psX509Cert_t *potentialIssuers) +{ + char *url; + unsigned char *crlBuf; + uint32_t urlLen, crlBufLen; + psX509Crl_t *crl; + psX509Cert_t *sc, *ic; + int32 numLoaded = 0; + + sc = cert; + while(sc) { + if (psX509GetCRLdistURL(sc, &url, &urlLen) > 0) { + /* url need not be freed. It points into cert structure */ + if (fetchCRL(NULL, url, urlLen, &crlBuf, &crlBufLen) < 0){ + _psTrace("Unable to fetch CRL\n"); + sc = sc->next; + continue; + } + /* Convert the CRL stream into our structure */ + if (psX509ParseCRL(pool, &crl, crlBuf, crlBufLen) < 0) { + _psTrace("Unable to parse CRL\n"); + psFree(crlBuf, pool); + sc = sc->next; + continue; + } + psFree(crlBuf, pool); + + /* Adding the CRL to the global cache. This local crl is now the + same memory as the entry in the global cache and is managed + there. Freeing will now be done with psCRL_DeleteAll at + application closure */ + psCRL_Update(crl, 1); /* The 1 will delete old CRLs */ + ++numLoaded; + + /* Important to separate the concept of the CRL authentication + from the cert authentication. Here, we run through the + list of potential issuers the caller thinks could work */ + for (ic = potentialIssuers; ic != NULL; ic = ic->next) { + if (psX509AuthenticateCRL(ic, crl, NULL) > 0) { + _psTrace("NOTE: Able to authenticate CRL\n"); + break; /* Stop looking */ + } + } + if (crl->authenticated == 0) { + /* If none of our potential issuers were able to authenticate, + let's just run through our own "cert" chain as well. + The reason we are doing this is to allow this function + to handle cases where the "cert" is part of a server + cert chain where the issuer is included as part of that + CERTIFICATE message. That is what we are testing here. + The potentialIssuers will typically be the loaded CA + files and that will catch the cases where the parent-most + certificate of the server chain will need to be + authenticated */ + for (ic = cert; ic != NULL; ic = ic->next) { + if (psX509AuthenticateCRL(ic, crl, NULL) > 0) { + _psTrace("NOTE: Able to authenticate CRL\n"); + break; /* Stop looking */ + } + } + } + + /* Regardless of whether or not we could authenticate the CRL, + run the function that recalculates the revokedStatus of + the certificate itself. REQUIRES g_CRL */ + psCRL_determineRevokedStatus(sc); + } + sc = sc->next; + } + _psTraceInt("CRLs loaded: %d\n", numLoaded); + 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 + 0 - Success */ static unsigned char crl_getHdr[] = "GET "; #define GET_OH_LEN 4 @@ -1347,26 +1647,28 @@ static unsigned char crl_acceptHdr[] = "\r\nAccept: */*\r\n\r\n"; #define HOST_ADDR_LEN 64 /* max to hold 'www.something.com' */ #define GET_REQ_LEN 128 /* max to hold http GET request */ -#define CRL_BUF_SIZE 4096 /* max size of incoming CRL */ -int32 crlCb(psPool_t *pool, psX509Cert_t *CA, int append, char *url, - uint32 urlLen) +#define HTTP_REPLY_CHUNK_SIZE 2048 + +int32 fetchCRL(psPool_t *pool, char *url, uint32_t urlLen, + unsigned char **crlBuf, uint32_t *crlBufLen) { SOCKET fd; struct hostent *ip; struct in_addr intaddr; char *pageStart, *replyPtr, *ipAddr; char hostAddr[HOST_ADDR_LEN], getReq[GET_REQ_LEN]; - char crlBuf[CRL_BUF_SIZE]; int hostAddrLen, getReqLen, pageLen; - int32 transferred; + int32 transferred, sawOK, sawContentLength, grown; int32 err, httpUriLen, port, offset; - uint32 crlBinLen; + unsigned char crlChunk[HTTP_REPLY_CHUNK_SIZE]; + unsigned char *crlBin; /* allocated */ + uint32_t crlBinLen; /* Is URI in expected URL form? */ if (strstr(url, "http://") == NULL) { if (strstr(url, "https://") == NULL) { - _psTraceStr("crlCb: Unsupported CRL URI: %s\n", url); + _psTraceStr("fetchCRL: Unsupported CRL URI: %s\n", url); return -1; } httpUriLen = 8; @@ -1378,25 +1680,25 @@ int32 crlCb(psPool_t *pool, psX509Cert_t *CA, int append, char *url, /* Parsing host and page and setting up IP address and GET request */ if ((pageStart = strchr(url + httpUriLen, '/')) == NULL) { - _psTrace("crlCb: No host/page divider found\n"); + _psTrace("fetchCRL: No host/page divider found\n"); return -1; } if ((hostAddrLen = (int)(pageStart - url) - httpUriLen) > HOST_ADDR_LEN) { - _psTrace("crlCb: HOST_ADDR_LEN needs to be increased\n"); + _psTrace("fetchCRL: HOST_ADDR_LEN needs to be increased\n"); return -1; /* ipAddr too small to hold */ } memset(hostAddr, 0, HOST_ADDR_LEN); memcpy(hostAddr, url + httpUriLen, hostAddrLen); if ((ip = gethostbyname(hostAddr)) == NULL) { - _psTrace("crlCb: gethostbyname failed\n"); + _psTrace("fetchCRL: gethostbyname failed\n"); return -1; } memcpy((char *) &intaddr, (char *) ip->h_addr_list[0], (size_t) ip->h_length); if ((ipAddr = inet_ntoa(intaddr)) == NULL) { - _psTrace("crlCb: inet_ntoa failed\n"); + _psTrace("fetchCRL: inet_ntoa failed\n"); return -1; } @@ -1404,7 +1706,7 @@ int32 crlCb(psPool_t *pool, psX509Cert_t *CA, int append, char *url, getReqLen = pageLen + hostAddrLen + GET_OH_LEN + HTTP_OH_LEN + HOST_OH_LEN + ACCEPT_OH_LEN; if (getReqLen > GET_REQ_LEN) { - _psTrace("crlCb: GET_REQ_LEN needs to be increased\n"); + _psTrace("fetchCRL: GET_REQ_LEN needs to be increased\n"); return -1; } @@ -1430,7 +1732,7 @@ int32 crlCb(psPool_t *pool, psX509Cert_t *CA, int append, char *url, /* Connect and send */ fd = lsocketConnect(ipAddr, port, &err); if (fd == INVALID_SOCKET || err != PS_SUCCESS) { - _psTraceInt("crlCb: socketConnect failed: %d\n", err); + _psTraceInt("fetchCRL: socketConnect failed: %d\n", err); return PS_PLATFORM_FAIL; } @@ -1438,7 +1740,7 @@ int32 crlCb(psPool_t *pool, psX509Cert_t *CA, int append, char *url, offset = 0; while (getReqLen) { if ((transferred = send(fd, getReq + offset, getReqLen, 0)) < 0) { - _psTraceInt("crlCb: socket send failed: %d\n", errno); + _psTraceInt("fetchCRL: socket send failed: %d\n", errno); close(fd); return PS_PLATFORM_FAIL; } @@ -1446,45 +1748,138 @@ int32 crlCb(psPool_t *pool, psX509Cert_t *CA, int append, char *url, offset += transferred; } - /* Not a good full recv */ - if ((transferred = recv(fd, crlBuf, CRL_BUF_SIZE, 0)) <= 0) { - _psTrace("crlCb: socket recv closed or failed\n"); - close(fd); - return PS_PLATFORM_FAIL; - } - if (transferred == CRL_BUF_SIZE) { - /* CRL larger than max */ - _psTrace("crlCb: CRL_BUF_SIZE needs to be increased\n"); - close(fd); - return -1; + /* Get a chunk at a time so we can peek at the size on the first chunk + and allocate the correct CRL size */ + crlBin = NULL; + *crlBuf = NULL; + *crlBufLen = 0; + sawOK = sawContentLength = 0; + + /* This recv loop is not 100%. The parse is looking for a few specific + strings in the HTTP header to get initial status, content length, + and \r\n\r\n for beginning of CRL data. If a recv happens to fall right + on the boundary of any of these patterns, the behavior is undefined. + There are some asserts sprinked around to notify if this happens. + It SHOULD be sufficient to keep a decent size HTTP_REPLLY_CHUNK_SIZE + that you can be pretty sure will hold the entire HTTP header but + the "recv" call itself is also a factor in how many bytes will be + recevied in the first call */ + while ((transferred = recv(fd, crlChunk, HTTP_REPLY_CHUNK_SIZE, 0)) > 0) { + + if (crlBin == NULL) { + /* Still getting the details of the HTTP response */ + /* Did we get an OK response? */ + if (sawOK == 0) { + if (strstr((const char *)crlChunk, "200 OK") == NULL) { + /* First chunk. Should be plenty large enough to hold */ + _psTrace("fetchCRL: server reply was not '200 OK'\n"); + close(fd); + return -1; + } + sawOK++; + } + /* Length parse */ + if (sawContentLength == 0) { + if ((replyPtr = strstr((const char *)crlChunk, + "Content-Length: ")) == NULL) { + + /* Apparently Content-Length is not always going to be + there. See if we have the end of the header instead */ + if ((replyPtr = strstr((const char *)crlChunk, "\r\n\r\n")) + == NULL) { + continue; /* saw neither. keep trying */ + } + /* Saw \r\n\r\n but no Content-Length: can't allocate full + CRL buffer at once so work in chunks */ + crlBinLen = HTTP_REPLY_CHUNK_SIZE; + } else { + /* Got the Content-Length: as expected */ + sawContentLength++; + + /* Possible cut off right at Content-Length here which + would be a pain. This assert is seeing if there are + at least 8 more bytes in the chunk to read the + integer out of. If you hit this, some partial + parsing will need to be instrumented... or change + the chunk size if this is truly a chunk boundary */ + psAssert((replyPtr + 16) < + (char*)&(crlChunk[HTTP_REPLY_CHUNK_SIZE - 24])); + + + /* Magic 16 is length of "Content-Length: " */ + crlBinLen = (int)atoi(replyPtr + 16); + } + } + + + /* Data begins after CRLF CRLF */ + if ((replyPtr = strstr((const char *)crlChunk, "\r\n\r\n")) + == NULL) { + continue; + } + /* Possible cut off right at data start here which + would be a pain. This assert is seeing if there are + 4 more bytes in the chunk to advance past. If you hit this, + some partial parsing will need to be instrumented... or change + the chunk size if this is truly a chunk boundary */ + psAssert((replyPtr+4) < (char*)&(crlChunk[HTTP_REPLY_CHUNK_SIZE])); + replyPtr += 4; /* Move past that "\r\n\r\n" to get to start */ + + /* Allocate the CRL buffer. Will be full size if sawContentLength */ + if ((crlBin = psMalloc(pool, crlBinLen)) == NULL) { + _psTrace("fetchCRL: Memory allocation error for CRL buffer\n"); + close(fd); + return -1; + } + + /* So how much do we actually have to copy our of first chunk? */ + transferred = transferred - (replyPtr - (char*)crlChunk); + + if (sawContentLength) { + /* Will march crlBin forward so just assign output crlBuf now */ + *crlBuf = crlBin; + *crlBufLen = crlBinLen; + memcpy(crlBin, replyPtr, transferred); + crlBin += transferred; + psAssert((crlBin - *crlBuf) <= crlBinLen); + } else { + grown = 1; + /* Keep track of index to monitor size */ + crlBinLen = transferred; + memcpy(crlBin, replyPtr, transferred); + } + } else { + /* subsequent recv calls */ + if (sawContentLength) { + memcpy(crlBin, crlChunk, transferred); + crlBin += transferred; + psAssert((crlBin - *crlBuf) <= crlBinLen); + } else { + if (transferred + crlBinLen > (HTTP_REPLY_CHUNK_SIZE * grown)) { + /* not enough room. psRealloc */ + grown++; + crlBin = psRealloc(crlBin, HTTP_REPLY_CHUNK_SIZE * grown, + pool); + } + memcpy(crlBin + crlBinLen, crlChunk, transferred); + crlBinLen += transferred; + } + } } close(fd); - - /* Did we get an OK response? */ - if (strstr(crlBuf, "200 OK") == NULL) { - _psTrace("crlCb: server reply was not '200 OK'\n"); - return -1; - } - /* Length parse */ - if ((replyPtr = strstr(crlBuf, "Content-Length: ")) == NULL) { - return -1; - } - crlBinLen = (int)atoi(replyPtr + 16); - - /* Data begins after CRLF CRLF */ - if ((replyPtr = strstr(crlBuf, "\r\n\r\n")) == NULL) { - return -1; - } - /* A sanity test that the length matches the remainder */ - if ((transferred - (replyPtr - crlBuf) - 4) != crlBinLen) { - return -1; + if (sawContentLength == 0) { + /* These have been changing as we grow */ + *crlBuf = crlBin; + *crlBufLen = crlBinLen; + } else { + psAssert(crlBinLen == (crlBin - *crlBuf)); } - /* Lastly, pass the CRL to matrixSslLoadCRL to parse, perform signature - validation, and cache the revoked certificates for this CA */ - return matrixSslLoadCRL(pool, CA, append, replyPtr + 4, crlBinLen, NULL); + return 0; + } -#endif +#endif /* USE_CRL */ + /******************************************************************************/ /* diff --git a/apps/ssl/server.c b/apps/ssl/server.c index 77bdd9d..1c0108d 100644 --- a/apps/ssl/server.c +++ b/apps/ssl/server.c @@ -49,14 +49,15 @@ #define ALLOW_ANON_CONNECTIONS 1 #define SEND_CLOSURE_ALERT -/* Directory path to MatrixSSL testkeys */ +/* Default keys if nothing provided on command line */ #define KEY_DIR "../../" -const static char certFile[] = "testkeys/RSA/2048_RSA.pem"; -const static char privkeyFile[] = "testkeys/RSA/2048_RSA_KEY.pem"; +const static char g_defaultCertFile[] = "testkeys/RSA/2048_RSA.pem"; +const static char g_defaultPrivkeyFile[] = "testkeys/RSA/2048_RSA_KEY.pem"; +const static char g_defaultCAFile[] = "testkeys/RSA/2048_RSA_CA.pem"; #ifdef REQUIRE_DH_PARAMS -const static char dhParamFile[] = "testkeys/DH/1024_DH_PARAMS.pem"; +const static char g_defaultDHParamFile[] = "testkeys/DH/1024_DH_PARAMS.pem"; #endif /********************************** Defines ***********************************/ @@ -78,6 +79,18 @@ const static char dhParamFile[] = "testkeys/DH/1024_DH_PARAMS.pem"; static DLListEntry g_conns; static int32 g_exitFlag; +static int g_port; +static int g_version; +static int g_disabledCiphers; +static uint16_t g_disabledCipher[SSL_MAX_DISABLED_CIPHERS]; + +#define MAX_KEYFILE_PATH 256 +#define MAX_KEYFILE_NAME 32 +static char g_keyfilePath[MAX_KEYFILE_PATH]; +static char g_privkeyFile[MAX_KEYFILE_NAME]; +static char g_identityCert[MAX_KEYFILE_NAME]; +static char g_dhParamFile[MAX_KEYFILE_NAME]; +static char g_password[32]; static unsigned char g_httpResponseHdr[] = "HTTP/1.0 200 OK\r\n" "Server: MatrixSSL/" MATRIXSSL_VERSION "\r\n" @@ -88,7 +101,24 @@ static unsigned char g_httpResponseHdr[] = "HTTP/1.0 200 OK\r\n" "\r\n" "MatrixSSL"; -/****************************** Local Functions *******************************/ +#ifdef USE_STATELESS_SESSION_TICKETS +static int32 sessTicketCb(void *keys, unsigned char name[16], short found); + +/* SAMPLE KEYS: DO NOT USE IN PRODUCTION */ +static unsigned char sessTicketSymKey[32] = { + 0x2A, 0x34, 0xC2, 0x11, 0x45, 0x8F, 0x3D, 0x08, + 0x2A, 0x34, 0xC2, 0x11, 0x45, 0x8F, 0x3D, 0x08, + 0x2A, 0x34, 0xC2, 0x11, 0x45, 0x8F, 0x3D, 0x08, + 0x2A, 0x34, 0xC2, 0x11, 0x45, 0x8F, 0x3D, 0x08}; + +static unsigned char sessTicketMacKey[32] = { + 0x2A, 0x34, 0xC2, 0x11, 0x45, 0x8F, 0x3D, 0x08, + 0x2A, 0x34, 0xC2, 0x11, 0x45, 0x8F, 0x3D, 0x08, + 0x2A, 0x34, 0xC2, 0x11, 0x45, 0x8F, 0x3D, 0x08, + 0x2A, 0x34, 0xC2, 0x11, 0x45, 0x8F, 0x3D, 0x08}; +#endif + +/***************************** Static Prototypes ******************************/ static int32 selectLoop(sslKeys_t *keys, SOCKET lfd); static int32 httpWriteResponse(httpConn_t *conn); @@ -102,6 +132,43 @@ static void sigintterm_handler(int i); static int32 sighandlers(void); #endif /* POSIX */ +/************************ Handshake Callback Functions ************************/ +/* A server will make use of a certificate callback if client authentication + is being used. This callback will be invoked during the handshake to + allow application level inspection of the client certificate and halt + the connection if required. See the documentation for more information + on the Certificte Callback function */ +int32_t certCb(ssl_t *ssl, psX509Cert_t *cert, int32_t alert) +{ + return alert; +} + + +#ifdef USE_STATELESS_SESSION_TICKETS +/* This callback will be invoked each time a client sends a session ticket and + can be used as an opportunity for the application to locate and load the + correct key or to void the ticket and revert to a full handshake. See + the API documenation for matrixSslSetSessionTicketCallback for more info */ +int32 sessTicketCb(void *keys, unsigned char name[16], short found) +{ + if (found) { + /* Was already cached */ + return PS_SUCCESS; + } + /* Example. If name was located, the keys would be loaded this way */ + return matrixSslLoadSessionTicketKeys((sslKeys_t*)keys, name, + sessTicketSymKey, 32, sessTicketMacKey, 32); +} +#endif + +void SNIcallback(void *ssl, char *hostname, int32 hostnameLen, + sslKeys_t **newKeys) +{ + ssl_t *lssl = ssl; + *newKeys = lssl->keys; + +} + /******************************************************************************/ /** Display connections per second (if more than 0), at most once per second @@ -229,12 +296,14 @@ static int32 selectLoop(sslKeys_t *keys, SOCKET lfd) memset(&options, 0x0, sizeof(sslSessOpts_t)); options.userPtr = keys; + //options.extendedMasterSecret = 1; /* Require */ if ((rc = matrixSslNewServerSession(&cp->ssl, keys, NULL, &options)) < 0) { close(fd); continue; } + matrixSslRegisterSNICallback(cp->ssl, SNIcallback); cp->fd = fd; cp->timeout = SSL_TIMEOUT; @@ -574,10 +643,172 @@ static int32 httpWriteResponse(httpConn_t *cp) static void usage(void) { - printf( "This application takes no runtime parameters.\n" - "Configuration is through defines in the source.\n"); + printf( + "\nusage: server { options }\n" + "\n" + "Options can be one or more of the following:\n" + "\n" + "-c - Server certificate file\n" + "-k - Server private key file of certificate\n" + "-p - Private key password\n" + "-d - Diffie-Hellman parameters file\n" + "-D - Directory path to certificate, private key, \n" + " and Diffie-Hellman parameter files\n" + "-P - Port number\n" + "-h - Help, print usage and exit\n" + "-x - Cipher suites to disable\n" + " Example cipher numbers:\n" + " - '53' TLS_RSA_WITH_AES_256_CBC_SHA\n" + " - '47' TLS_RSA_WITH_AES_128_CBC_SHA\n" + " - '10' SSL_RSA_WITH_3DES_EDE_CBC_SHA\n" + " - '5' SSL_RSA_WITH_RC4_128_SHA\n" + " - '4' SSL_RSA_WITH_RC4_128_MD5\n" + "-v - SSL/TLS version to use\n" + " - '0' SSL 3.0\n" + " - '1' TLS 1.0\n" + " - '2' TLS 1.1\n" + " - '3' TLS 1.2 (default)\n" + "\n"); + } +/* Returns number of cipher numbers found, or -1 if an error. */ +#include +static int32_t parse_cipher_list(char *cipherListString, + uint16_t cipher_array[], uint8_t size_of_cipher_array) +{ + uint32 numCiphers, cipher; + char *endPtr; + + /* Convert the cipherListString into an array of cipher numbers. */ + numCiphers = 0; + while (cipherListString != NULL) { + cipher = strtol(cipherListString, &endPtr, 10); + if (endPtr == cipherListString) { + printf("The remaining cipherList has no cipher numbers - '%s'\n", + cipherListString); + return -1; + } else if (size_of_cipher_array <= numCiphers) { + printf("Too many cipher numbers supplied. limit is %d\n", + size_of_cipher_array); + return -1; + } + cipher_array[numCiphers++] = cipher; + while (*endPtr != '\0' && !isdigit(*endPtr)) { + endPtr++; + } + cipherListString = endPtr; + if (*endPtr == '\0') { + break; + } + } + + return numCiphers; +} + +/* Return 0 on good set of cmd options, return -1 if a bad cmd option is + encountered OR a request for help is seen (i.e. '-h' option). */ +static int32 process_cmd_options(int32 argc, char **argv) +{ + int optionChar, str_len, version, numCiphers; + char *cipherListString; + + + memset(g_keyfilePath, 0, MAX_KEYFILE_PATH); + memset(g_privkeyFile, 0, sizeof(MAX_KEYFILE_NAME)); + memset(g_identityCert, 0, sizeof(MAX_KEYFILE_NAME)); + memset(g_dhParamFile, 0, sizeof(MAX_KEYFILE_NAME)); + memset(g_password, 0, 32); + + g_port = HTTPS_PORT; + g_version = 3; + g_disabledCiphers = 0; + + opterr = 0; + while ((optionChar = getopt(argc, argv, "c:d:D:hk:p:P:v:x:")) != -1) + { + switch (optionChar) + { + case 'h': + return -1; + + case 'x': + // Ciphers to DISABLE! + // Convert the cipherListString into an array of cipher numbers. + cipherListString = optarg; + numCiphers = parse_cipher_list(cipherListString, g_disabledCipher, + SSL_MAX_DISABLED_CIPHERS); + if (numCiphers <= 0) { + return -1; + } + g_disabledCiphers = numCiphers; + break; + + case 'D': + // Directory for key and cert location + str_len = strlen(optarg); + if (str_len > MAX_KEYFILE_PATH - 1) { + return -1; + } + strncpy(g_keyfilePath, optarg, str_len); + break; + + case 'c': + // Certfile + str_len = strlen(optarg); + if (str_len > MAX_KEYFILE_NAME - 1) { + return -1; + } + strncpy(g_identityCert, optarg, str_len); + break; + + case 'd': + // Diffie-Hellman parameters + str_len = strlen(optarg); + if (str_len > MAX_KEYFILE_NAME - 1) { + return -1; + } + strncpy(g_dhParamFile, optarg, str_len); + break; + + + case 'k': + // Keyfile + str_len = strlen(optarg); + if (str_len > MAX_KEYFILE_NAME - 1) { + return -1; + } + strncpy(g_privkeyFile, optarg, str_len); + break; + + case 'p': + // password + str_len = strlen(optarg); + if (str_len > MAX_KEYFILE_NAME - 1) { + return -1; + } + strncpy(g_password, optarg, str_len); + break; + + case 'P': + g_port = atoi(optarg); + break; + + case 'v': + version = atoi(optarg); + if (version < 0 || version > 3) { + printf("Invalid version: %d\n", version); + return -1; + } + g_version = version; + break; + } + } + + return 0; +} + + /******************************************************************************/ /* Main non-blocking SSL server @@ -589,16 +820,15 @@ int32 main(int32 argc, char **argv) int32 err, rc; #ifdef WIN32 WSADATA wsaData; +#endif +#ifdef USE_STATELESS_SESSION_TICKETS + unsigned char randKey[16]; #endif char certpath[FILENAME_MAX]; char keypath[FILENAME_MAX]; + char capath[FILENAME_MAX]; sslKeys_t *keys = NULL; - - if (argc > 1) { - usage(); - return 0; - } - + #ifdef WIN32 WSAStartup(MAKEWORD(1, 1), &wsaData); #endif @@ -621,24 +851,109 @@ int32 main(int32 argc, char **argv) if (matrixSslNewKeys(&keys, NULL) < 0) { return -1; } - snprintf(certpath, FILENAME_MAX - 1, "%s/%s", KEY_DIR, certFile); - snprintf(keypath, FILENAME_MAX - 1, "%s/%s", KEY_DIR, privkeyFile); - if ((rc = matrixSslLoadRsaKeys(keys, certpath, keypath, NULL, NULL)) < 0) { - _psTrace("Unable to load static key material. Exiting\n"); - return rc; + + if (0 != process_cmd_options(argc, argv)) { + usage(); + return 0; + } + +#ifdef USE_OCSP + OCSPRequestAndResponseTest(); +#endif + +#ifdef USE_STATELESS_SESSION_TICKETS + _psTrace("Session Ticket resumption enabled\n"); + _psTrace("WARNING: Do not use sample session ticket keys in production\n"); + matrixSslSetSessionTicketCallback(keys, sessTicketCb); + psGetEntropy(randKey, 16, NULL); + if (matrixSslLoadSessionTicketKeys(keys, randKey, + sessTicketSymKey, 32, sessTicketMacKey, 32) < 0) { + _psTrace("Error loading session ticket encryption key\n"); + } +#endif + + + /* Set the certpath and keypath as the defaults or the user provided */ + if (g_identityCert[0] != 0) { + // User provided a cert + if (g_keyfilePath[0] != 0) { + snprintf(certpath, FILENAME_MAX - 1, "%s/%s", + g_keyfilePath, g_identityCert); + } else { + snprintf(certpath, FILENAME_MAX - 1, "%s", g_identityCert); + } + } else { + // Default cert + _psTrace("WARNING: Do not use sample certificate file in production\n"); + snprintf(certpath, FILENAME_MAX - 1, "%s/%s", + KEY_DIR, g_defaultCertFile); + } + + if (g_privkeyFile[0] != 0) { + // User provided a key + if (g_keyfilePath[0] != 0) { + snprintf(keypath, FILENAME_MAX - 1, "%s/%s", + g_keyfilePath, g_privkeyFile); + } else { + snprintf(keypath, FILENAME_MAX - 1, "%s", g_privkeyFile); + } + } else { + // Default key + _psTrace("WARNING: Do not use sample private key file in production\n"); + snprintf(keypath, FILENAME_MAX - 1, "%s/%s", + KEY_DIR, g_defaultPrivkeyFile); + } + + snprintf(capath, FILENAME_MAX - 1, "%s/%s", KEY_DIR, g_defaultCAFile); + + /* Still don't have a generic key loading function. Try RSA first and + then ECC if that doesn't load */ + if ((rc = matrixSslLoadRsaKeys(keys, certpath, keypath, g_password, capath)) < 0) { +#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 } + #ifdef REQUIRE_DH_PARAMS - snprintf(certpath, FILENAME_MAX - 1, "%s/%s", KEY_DIR, dhParamFile); + if (g_dhParamFile[0] != 0) { + // User provided DH params + if (g_keyfilePath[0] != 0) { + snprintf(certpath, FILENAME_MAX - 1, "%s/%s", + g_keyfilePath, g_dhParamFile); + } else { + snprintf(certpath, FILENAME_MAX - 1, "%s", g_dhParamFile); + } + } else { + // Default DH params + snprintf(certpath, FILENAME_MAX - 1, "%s/%s", + KEY_DIR, g_defaultDHParamFile); + } if ((rc = matrixSslLoadDhParams(keys, certpath)) < 0) { _psTrace("Unable to load static key material. Exiting\n"); return rc; } #endif + + /* Were any cipher suites disabled? */ + if (g_disabledCiphers > 0) { + for (rc = 0; rc < g_disabledCiphers; rc++) { + /* Global disable. Per-session disables would be done immediately + following matrixSslNewServerSession if desired */ + matrixSslSetCipherSuiteEnabledStatus(NULL, g_disabledCipher[rc], + PS_FALSE); + } + } /* Create the listening socket that will accept incoming connections */ - if ((lfd = lsocketListen(HTTPS_PORT, &err)) == INVALID_SOCKET) { - _psTraceInt("Can't listen on port %d\n", HTTPS_PORT); + if ((lfd = lsocketListen(g_port, &err)) == INVALID_SOCKET) { + _psTraceInt("Can't listen on port %d\n", g_port); goto L_EXIT; } diff --git a/common.mk b/common.mk index a730a69..ab02f08 100755 --- a/common.mk +++ b/common.mk @@ -85,11 +85,11 @@ ifdef MATRIX_DEBUG OPT:=-O0 -g -DDEBUG -Wall #OPT+=-Wconversion STRIP:=test # no-op -else +endif +ifndef MATRIX_DEBUG + OPT:=-O3 -Wall # Default compile for speed ifneq (,$(findstring -none,$(CCARCH))) OPT:=-Os -Wall # Compile bare-metal for size - else - OPT:=-O3 -Wall # Compile all others for speed endif STRIP:=strip endif @@ -98,7 +98,8 @@ CFLAGS+=$(OPT) # Detect multicore and do parallel build. Uncomment if desired: #> ifneq (,$(findstring -linux,$(CCARCH))) #> JOBS:=-j$(shell grep -ic processor /proc/cpuinfo) -#> else ifneq (,$(findstring apple,$(CCARCH))) +#> endif +#> ifneq (,$(findstring apple,$(CCARCH))) #> JOBS:=-j$(shell sysctl -n machdep.cpu.thread_count) #> endif @@ -120,15 +121,17 @@ ifneq (,$(findstring x86_64-,$(CCARCH))) CFLAGS+=-maes -mpclmul -msse4.1 STROPTS+=", AES-NI ASM" endif - else ifneq (,$(findstring apple,$(CCARCH))) + endif + ifneq (,$(findstring apple,$(CCARCH))) ifeq ($(shell sysctl -n hw.optional.aes),1) CFLAGS+=-maes -mpclmul -msse4.1 STROPTS+=", AES-NI ASM" endif endif +endif -# 32 Bit Intel Edison Target -else ifneq (,$(findstring i586-,$(CCARCH))) +# 32 Bit Intel Target +ifneq (,$(findstring i586-,$(CCARCH))) CFLAGS+=-m32 ifneq (,$(findstring edison,$(shell uname -n))) ifneq (,$(findstring -O3,$(OPT))) @@ -140,22 +143,25 @@ else ifneq (,$(findstring i586-,$(CCARCH))) else STROPTS+=", 32-bit Intel RSA/ECC ASM" endif +endif -# 32 Bit Intel Target -else ifneq (,$(findstring i686-,$(CCARCH))) +# 32 Bit Intel Target Alternate +ifneq (,$(findstring i686-,$(CCARCH))) CFLAGS+=-m32 STROPTS+=", 32-bit Intel RSA/ECC ASM" +endif # MIPS Target -else ifneq (,$(findstring mips-,$(CCARCH))) +ifneq (,$(findstring mips-,$(CCARCH))) STROPTS+=", 32-bit MIPS RSA/ECC ASM" +endif # MIPS64 Target -else ifneq (,$(filter mips%64-,$(CCARCH))) -# STROPTS+=", 64-bit MIPS64 RSA/ECC ASM" +ifneq (,$(filter mips%64-,$(CCARCH))) +endif # ARM Target -else ifneq (,$(findstring arm,$(CCARCH))) +ifneq (,$(findstring arm,$(CCARCH))) STROPTS+=", 32-bit ARM RSA/ECC ASM" ifneq (,$(findstring linux-,$(CCARCH))) HARDWARE:=$(shell sed -n '/Hardware[ \t]*: / s/// p' /proc/cpuinfo) @@ -189,13 +195,14 @@ else ifneq (,$(findstring arm,$(CCARCH))) undefine HARDWARE endif endif - endif ifdef MATRIX_DEBUG CFLAGS+=-ffunction-sections -fdata-sections -else -CFLAGS+=-ffunction-sections -fdata-sections -fomit-frame-pointer +endif +ifndef MATRIX_DEBUG +CFLAGS_OMIT_FRAMEPOINTER=-fomit-frame-pointer +CFLAGS+=-ffunction-sections -fdata-sections $(CFLAGS_OMIT_FRAMEPOINTER) endif # If we're using clang (it may be invoked via 'cc' or 'gcc'), @@ -220,15 +227,20 @@ ifdef USE_OPENSSL_CRYPTO # Statically link against a given openssl tree CFLAGS+=-I$(OPENSSL_ROOT)/include LDFLAGS+=$(OPENSSL_ROOT)/libcrypto.a -ldl - else ifneq (,$(findstring -apple,$(CCARCH))) + endif + ifneq (,$(findstring -apple,$(CCARCH))) # Dynamically link against the sytem default openssl tree # Apple has deprecated the built in openssl, so supress warnings here CFLAGS+=-Wno-error=deprecated-declarations -Wno-deprecated-declarations LDFLAGS+=-lcrypto - else ifneq (,$(findstring -linux,$(CCARCH))) + OPENSSL_ROOT=included_in_the_OS + endif + ifneq (,$(findstring -linux,$(CCARCH))) # Dynamically link against the sytem default openssl tree LDFLAGS+=-lcrypto - else + OPENSSL_ROOT=shall_be_included_in_distribution + endif + ifndef OPENSSL_ROOT $(error Please define OPENSSL_ROOT) endif CFLAGS+=-DUSE_OPENSSL_CRYPTO @@ -242,7 +254,8 @@ ifdef USE_LIBSODIUM_CRYPTO # Statically link against a given libsodium CFLAGS+=-I$(LIBSODIUM_ROOT)/include LDFLAGS+=$(LIBSODIUM_ROOT)/.libs/libsodium.a - else + endif + ifndef LIBSODIUM_ROOT $(error Please define LIBSODIUM_ROOT) endif CFLAGS+=-DUSE_LIBSODIUM_CRYPTO @@ -254,23 +267,27 @@ ifneq (,$(findstring -linux,$(CCARCH))) OSDEP:=POSIX #For USE_HIGHRES_TIME LDFLAGS+=-lrt +endif # OS X Target -else ifneq (,$(findstring -apple,$(CCARCH))) +ifneq (,$(findstring -apple,$(CCARCH))) OSDEP:=POSIX CFLAGS+=-isystem -I/usr/include +endif # Bare Metal / RTOS Target -else ifneq (,$(findstring -none,$(CCARCH))) +ifneq (,$(findstring -none,$(CCARCH))) OSDEP:=METAL CFLAGS+=-fno-exceptions -fno-unwind-tables -fno-non-call-exceptions -fno-asynchronous-unwind-tables -ffreestanding -fno-builtin -nostartfiles ifneq (,$(findstring cortex-,$(CPU))) CFLAGS+=-mthumb -mcpu=$(CPU) -mslow-flash-data ifeq (cortex-m4,$(CPU)) CFLAGS+=-mcpu=cortex-m4 -mtune=cortex-m4 - else ifeq (cortex-m3,$(CPU)) + endif + ifeq (cortex-m3,$(CPU)) CFLAGS+=-mcpu=cortex-m3 -mtune=cortex-m3 -mfpu=vpf - else ifeq (cortex-m0,$(CPU)) + endif + ifeq (cortex-m0,$(CPU)) CFLAGS+=-mcpu=cortex-m0 -mtune=cortex-m0 -mfpu=vpf endif endif diff --git a/core/POSIX/osdep.c b/core/POSIX/osdep.c index db3b739..d018326 100644 --- a/core/POSIX/osdep.c +++ b/core/POSIX/osdep.c @@ -205,7 +205,7 @@ int64_t psDiffUsecs(psTime_t then, psTime_t now) now.tv_sec--; now.tv_nsec += 1000000000L; /* borrow 1 second worth of nsec */ } - return (int32)((now.tv_sec - then.tv_sec) * 1000) + + return (int32)((now.tv_sec - then.tv_sec) * 1000000) + ((now.tv_nsec - then.tv_nsec)/ 1000); } @@ -232,44 +232,48 @@ int32 psCompareTime(psTime_t a, psTime_t b, void *userPtr) MUTEX FUNCTIONS */ /******************************************************************************/ -static pthread_mutexattr_t attr; -/* - Module open and close -*/ -int osdepMutexOpen(void) -{ - int32 rc; +int32_t osdepMutexOpen(void) +{ + return PS_SUCCESS; +} + +void osdepMutexClose(void) +{ +} + +int32_t psCreateMutex(psMutex_t *mutex, uint32_t flags) +{ + pthread_mutexattr_t attr; + int rc; + + if (flags & ~PS_SHARED) { + psErrorInt("psCreateMutex unsupported flag %u\n", flags); + return PS_PLATFORM_FAIL; + } if ((rc = pthread_mutexattr_init(&attr)) < 0) { psErrorInt("pthread_mutexattr_init failed %d\n", rc); return PS_PLATFORM_FAIL; } - return PS_SUCCESS; -} - -int osdepMutexClose(void) -{ - if (pthread_mutexattr_destroy(&attr) != 0) { - psTraceCore("pthread_mutex_destroy failed\n"); - } - return PS_SUCCESS; -} - -/* - PScore Public API implementations -*/ -int32 psCreateMutex(psMutex_t *mutex) -{ - int32 err; - - if ((err = pthread_mutex_init(mutex, &attr)) != 0) { - psTraceIntCore("pthread_mutex_init failed %d\n", err); + if ((flags & PS_SHARED) && + (rc = pthread_mutexattr_setpshared(&attr, + PTHREAD_PROCESS_SHARED)) < 0) { + pthread_mutexattr_destroy(&attr); + psErrorInt("pthread_mutexattr shared failed %d\n", rc); return PS_PLATFORM_FAIL; } + if ((rc = pthread_mutex_init(mutex, &attr)) != 0) { + pthread_mutexattr_destroy(&attr); + psErrorInt("pthread_mutex_init failed %d\n", rc); + return PS_PLATFORM_FAIL; + } + if (pthread_mutexattr_destroy(&attr) != 0) { + psTraceCore("pthread_mutexattr_destroy failed\n"); + } return PS_SUCCESS; } -int32 psLockMutex(psMutex_t *mutex) +int32_t psLockMutex(psMutex_t *mutex) { if (pthread_mutex_lock(mutex) != 0) { psTraceCore("pthread_mutex_lock failed\n"); @@ -278,7 +282,7 @@ int32 psLockMutex(psMutex_t *mutex) return PS_SUCCESS; } -int32 psUnlockMutex(psMutex_t *mutex) +int32_t psUnlockMutex(psMutex_t *mutex) { if (pthread_mutex_unlock(mutex) != 0) { psTraceCore("pthread_mutex_unlock failed\n"); diff --git a/core/WIN32/osdep.c b/core/WIN32/osdep.c index 84de000..15db6bf 100644 --- a/core/WIN32/osdep.c +++ b/core/WIN32/osdep.c @@ -35,7 +35,7 @@ #include "../coreApi.h" #ifdef WIN32 -#include +#include /******************************************************************************/ /* TIME */ @@ -99,30 +99,32 @@ int32 psCompareTime(psTime_t a, psTime_t b, void *userPtr) #ifdef USE_MULTITHREADING -int osdepMutexOpen(void) +int32_t osdepMutexOpen(void) { return PS_SUCCESS; } -int osdepMutexClose(void) +void osdepMutexClose(void) { +} + +int32_t psCreateMutex(psMutex_t *mutex, uint32_t flags) +{ + if (flags) { + psErrorInt("psCreateMutex unsupported flag %u\n", flags); + return PS_PLATFORM_FAIL; + } + InitializeCriticalSection(mutex); /* Does not return a value */ return PS_SUCCESS; } -/* PScore Public API implementations */ -int32 psCreateMutex(psMutex_t *mutex) -{ - InitializeCriticalSection(mutex); - return PS_SUCCESS; -} - -int32 psLockMutex(psMutex_t *mutex) +int32_t psLockMutex(psMutex_t *mutex) { EnterCriticalSection(mutex); return PS_SUCCESS; } -int32 psUnlockMutex(psMutex_t *mutex) +int32_t psUnlockMutex(psMutex_t *mutex) { LeaveCriticalSection(mutex); return PS_SUCCESS; @@ -136,7 +138,6 @@ void psDestroyMutex(psMutex_t *mutex) /******************************************************************************/ /* ENTROPY */ - static HCRYPTPROV hProv; /* Crypto context for random bytes */ int osdepEntropyOpen(void) @@ -175,7 +176,7 @@ void osdepTraceClose(void) void _psTrace(const char *msg) { - printf(msg); + printf("%s", msg); } /* Message should contain one %s, unless value is NULL */ @@ -184,7 +185,7 @@ void _psTraceStr(const char *message, const char *value) if (value) { printf(message, value); } else { - printf(message); + printf("%s", message); } } diff --git a/core/coreApi.h b/core/coreApi.h index ae39025..15b4454 100644 --- a/core/coreApi.h +++ b/core/coreApi.h @@ -163,12 +163,15 @@ PSPUBLIC int32 psGetFileBuf(psPool_t *pool, const char *fileName, #endif /* MATRIX_USE_FILE_SYSTEM */ #ifdef USE_MULTITHREADING -PSPUBLIC int32 psCreateMutex(psMutex_t *mutex); -PSPUBLIC int32 psLockMutex(psMutex_t *mutex); -PSPUBLIC int32 psUnlockMutex(psMutex_t *mutex); +#define PS_SHARED 0x1 +PSPUBLIC int32_t psCreateMutex(psMutex_t *mutex, uint32_t flags); +PSPUBLIC int32_t psLockMutex(psMutex_t *mutex); +PSPUBLIC int32_t psUnlockMutex(psMutex_t *mutex); PSPUBLIC void psDestroyMutex(psMutex_t *mutex); #else -#define psCreateMutex(A) (PS_SUCCESS) +/** @note These are defines rather than inline functions because it allows +the caller to not allocate a mutex that will never be used. */ +#define psCreateMutex(A, B) (PS_SUCCESS) #define psLockMutex(A) (PS_SUCCESS) #define psUnlockMutex(A) (PS_SUCCESS) #define psDestroyMutex(A) diff --git a/core/osdep.h b/core/osdep.h index b57c631..8e89bb5 100644 --- a/core/osdep.h +++ b/core/osdep.h @@ -197,7 +197,12 @@ extern void osdepEntropyClose(void); #endif #endif -#if defined(POSIX) +#if defined(POSIX) || (defined(WIN32) && _MSC_VER >= 1600/*MSVC2010*/) + #if defined(WIN32) + #include + #define strcasecmp lstrcmpiA + #define snprintf _snprintf + #endif #include typedef int32_t int32; typedef uint32_t uint32; @@ -400,8 +405,8 @@ PSPUBLIC void _psErrorStr(const char *msg, const char *val); */ #ifdef USE_MULTITHREADING -extern int32 osdepMutexOpen(void); -extern int32 osdepMutexClose(void); +extern int32_t osdepMutexOpen(void); +extern void osdepMutexClose(void); #if defined(WIN32) typedef CRITICAL_SECTION psMutex_t; @@ -415,7 +420,6 @@ extern int32 osdepMutexClose(void); #else #error psMutex_t must be defined #endif /* OS specific mutex */ - #endif /* USE_MULTITHREADING */ /******************************************************************************/ diff --git a/core/psmalloc.h b/core/psmalloc.h index e101dbc..52552d2 100644 --- a/core/psmalloc.h +++ b/core/psmalloc.h @@ -68,7 +68,14 @@ #define psMemset memset #define psMemcpy memcpy -typedef int32 psPool_t; +/* + Support for memory allocation in order to avoid applications that redefine + malloc/free (see Perl) +*/ +__inline static void *psMallocNative(size_t size) { return malloc(size); } +__inline static void psFreeNative(void *ptr) { free(ptr); } + +typedef int32_t psPool_t; /******************************************************************************/ diff --git a/crypto/Makefile b/crypto/Makefile index 36a4d6d..54f9788 100755 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -29,6 +29,7 @@ SRC:=\ digest/md2.c \ keyformat/asn1.c \ keyformat/base64.c \ + keyformat/crl.c \ keyformat/pkcs.c \ keyformat/x509.c \ layer/matrix.c \ diff --git a/crypto/cryptoApi.h b/crypto/cryptoApi.h index af0323e..745ad11 100644 --- a/crypto/cryptoApi.h +++ b/crypto/cryptoApi.h @@ -39,7 +39,7 @@ extern "C" { #endif -#include "core/coreApi.h" /* Must be included first */ +#include "../core/coreApi.h" /* Must be included first */ #include "cryptoConfig.h" /* Must be included second */ #include "cryptolib.h" @@ -194,6 +194,10 @@ PSPUBLIC int32_t psAesInitGCM(psAesGcm_t *ctx, PSPUBLIC void psAesReadyGCM(psAesGcm_t *ctx, const unsigned char IV[AES_IVLEN], const unsigned char *aad, uint16_t aadLen); +PSPUBLIC int32_t psAesReadyGCMRandomIV(psAesGcm_t *ctx, + unsigned char IV[12], + const unsigned char *aad, uint16_t aadLen, + void *poolUserPtr); PSPUBLIC void psAesEncryptGCM(psAesGcm_t *ctx, const unsigned char *pt, unsigned char *ct, uint32_t len); @@ -201,6 +205,11 @@ PSPUBLIC int32_t psAesDecryptGCM(psAesGcm_t *ctx, const unsigned char *ct, uint32_t ctLen, unsigned char *pt, uint32_t ptLen); +PSPUBLIC int32_t psAesDecryptGCM2(psAesGcm_t *ctx, + const unsigned char *ct, + unsigned char *pt, uint32_t len, + const unsigned char *tag, uint32_t tagLen); + PSPUBLIC void psAesDecryptGCMtagless(psAesGcm_t *ctx, const unsigned char *ct, unsigned char *pt, uint32_t len); @@ -660,8 +669,34 @@ PSPUBLIC int32 psX509AuthenticateCert(psPool_t *pool, psX509Cert_t *subjectCert, void *hwCtx, void *poolUserPtr); #endif #ifdef USE_CRL -PSPUBLIC int32 psX509ParseCrl(psPool_t *pool, psX509Cert_t *CA, int append, - unsigned char *crlBin, int32 crlBinLen, void *poolUserPtr); +#define CRL_CHECK_EXPECTED 5 /* cert had a dist point but not fetched yet */ +#define CRL_CHECK_NOT_EXPECTED 6 /* cert didn't have dist point */ +#define CRL_CHECK_PASSED_AND_AUTHENTICATED 7 /* all completely good */ +#define CRL_CHECK_PASSED_BUT_NOT_AUTHENTICATED 8 /* had CRL but no auth done */ +#define CRL_CHECK_REVOKED_AND_AUTHENTICATED 9 +#define CRL_CHECK_REVOKED_BUT_NOT_AUTHENTICATED 10 +#define CRL_CHECK_CRL_EXPIRED 11 /* CRL expired. Revocation not tested */ + + +PSPUBLIC int32_t psX509ParseCRL(psPool_t *pool, psX509Crl_t **crl, + unsigned char *crlBin, int32 crlBinLen); +PSPUBLIC void psX509FreeCRL(psX509Crl_t *crl); +PSPUBLIC int32_t psX509GetCRLdistURL(psX509Cert_t *cert, char **url, + uint32_t *urlLen); +PSPUBLIC int32_t psX509AuthenticateCRL(psX509Cert_t *CA, psX509Crl_t *CRL, + void *poolUserPtr); + +/* CRL global cache management */ +PSPUBLIC int psCRL_Update(psX509Crl_t *crl, int deleteExisting); +PSPUBLIC int psCRL_Insert(psX509Crl_t *crl); +PSPUBLIC int psCRL_Remove(psX509Crl_t *crl); /* Doesn't delete! */ +PSPUBLIC int psCRL_Delete(psX509Crl_t *crl); +PSPUBLIC void psCRL_RemoveAll(); +PSPUBLIC void psCRL_DeleteAll(); +PSPUBLIC psX509Crl_t* psCRL_GetCRLForCert(psX509Cert_t *cert); +PSPUBLIC int32_t psCRL_isRevoked(psX509Cert_t *cert, psX509Crl_t *CRL); +PSPUBLIC int32_t psCRL_determineRevokedStatus(psX509Cert_t *cert); + #endif /* USE_CRL */ #endif /* USE_X509 */ diff --git a/crypto/cryptolib.h b/crypto/cryptolib.h index b4a65f3..a02cade 100644 --- a/crypto/cryptolib.h +++ b/crypto/cryptolib.h @@ -551,6 +551,11 @@ x = (((uint64)((y)[0] & 255))<<56)|(((uint64)((y)[1] & 255))<<48)| \ BLOCKSIZE <= 1 ? (unsigned char)0 : \ (unsigned char)(BLOCKSIZE - ((LEN) & (BLOCKSIZE - 1))) +#ifdef USE_CRL +extern int32_t psCrlOpen(); +extern void psCrlClose(); +#endif + #endif /* _h_PS_CRYPTOLIB */ /******************************************************************************/ diff --git a/crypto/keyformat/asn1.h b/crypto/keyformat/asn1.h index ca41c22..3440bb2 100644 --- a/crypto/keyformat/asn1.h +++ b/crypto/keyformat/asn1.h @@ -35,7 +35,7 @@ #ifndef _h_PS_ASN1 #define _h_PS_ASN1 -#include "crypto/cryptoConfig.h" +#include "../cryptoConfig.h" /******************************************************************************/ /* diff --git a/crypto/keyformat/crl.c b/crypto/keyformat/crl.c new file mode 100644 index 0000000..5f19f82 --- /dev/null +++ b/crypto/keyformat/crl.c @@ -0,0 +1,1167 @@ +/** + * @file crl.c + * @version $Format:%h%d$ + * + * Certificate Revocation List tools + */ +/* + * Copyright (c) 2013-2016 INSIDE Secure Corporation + * All Rights Reserved + * + * The latest version of this code is available at http://www.matrixssl.org + * + * This software is open source; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This General Public License does NOT permit incorporating this software + * into proprietary programs. If you are unable to comply with the GPL, a + * commercial license for this software may be purchased from INSIDE at + * http://www.insidesecure.com/ + * + * This program is distributed in WITHOUT ANY WARRANTY; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * http://www.gnu.org/copyleft/gpl.html + */ +/******************************************************************************/ + +#include "../cryptoApi.h" + +#ifdef USE_CRL +#ifdef USE_CERT_PARSE + +#ifdef USE_MULTITHREADING +static psMutex_t g_crlTableLock; +#endif + +/* Seems like many CRLs are not adhering to the specification that this + extension be present. That just leaves us with the DN to match against + if we disable this define. Not a big concern to disable it because the + authentication is either going to pass or fail based on sig validation */ +//#define ENFORCE_CRL_AUTH_KEY_ID_EXT + +static void internalFreeCRL(psX509Crl_t *crl); + +/* The global CRL cache is a linked list of psX509Crl_t structures. A + psX509Crl_t structure represents a single CRL file */ +static psX509Crl_t *g_CRL = NULL; + + +/* Invoked from psCryptoOpen */ +int32_t psCrlOpen() +{ +#ifdef USE_MULTITHREADING + psCreateMutex(&g_crlTableLock, 0); +#endif + return PS_SUCCESS; +} + +/* Invoked from psCryptoClose */ +void psCrlClose() +{ + psCRL_DeleteAll(); +#ifdef USE_MULTITHREADING + psDestroyMutex(&g_crlTableLock); +#endif +} + +/* Helper for CRL insert */ +static int internalCRLInsert(psX509Crl_t *crl) +{ + psX509Crl_t *next; + + if (crl == NULL) { + return 0; + } + + if (g_CRL == NULL) { + /* first one */ + g_CRL = crl; + return 1; + } + /* append */ + next = g_CRL; + if (g_CRL == crl) { + return 0; /* no pointer dups */ + } + while (next->next) { + next = next->next; + if (next == crl) { /* no pointer dups */ + return 0; + } + } + next->next = crl; + return 1; +} + +/* Blindly append a CRL to the g_CRL list. Consider psCRL_Update instead. + 1 - Added, 0 - Didn't */ +int psCRL_Insert(psX509Crl_t *crl) +{ + int rc; +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + rc = internalCRLInsert(crl); + +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + return rc; +} + +/* Helper for Remove and Delete to take a CRL out of g_CRL */ +static int internalShrinkCRLtable(psX509Crl_t *crl, int delete) +{ + psX509Crl_t *prev, *curr, *next; + + /* Return whether or not it was found in the list to help with the + standalone psX509FreeCRL call logic */ + + if (g_CRL == NULL || crl == NULL) { + return 0; + } + prev = NULL; + curr = g_CRL; + next = curr->next; + while (curr) { + if (curr == crl) { + if (delete) { + internalFreeCRL(crl); + } else { + curr->next = NULL; + } + if (prev == NULL && next == NULL) { + /* Only one in list */ + g_CRL = NULL; + } else if (prev == NULL && next != NULL) { + /* Removed first one in list */ + g_CRL = next; + } else if (prev != NULL) { + /* Removed middle or end */ + prev->next = next; + } + return 1; + } + prev = curr; + curr = curr->next; + if (curr) { + /* curr can be NULL if we never found crl */ + next = curr->next; + } + } + return 0; +} + +/* Remove a CRL from g_CRL but don't free the associated CRL */ +int psCRL_Remove(psX509Crl_t *crl) +{ + int rc; + +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + rc = internalShrinkCRLtable(crl, 0); + +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + return rc; +} + +/* Remove a CRL from g_CRL and free the associated CRL */ +int psCRL_Delete(psX509Crl_t *crl) +{ + int rc; + +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + rc = internalShrinkCRLtable(crl, 1); + +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + return rc; +} + +/* Remove all CRLs from g_CRL but don't free the associated memory. Assumes + the user will be using psX509FreeCRL later */ +void psCRL_RemoveAll() +{ + psX509Crl_t *curr, *next; + +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + curr = g_CRL; + next = curr->next; + while (next) { + next = curr->next; + curr->next = NULL; + curr = next; + } + g_CRL = NULL; +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ +} + +/* Remove all CRLs from g_CRL and free the associated memory */ +void psCRL_DeleteAll() +{ + psX509Crl_t *curr, *next; + +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + curr = g_CRL; + while (curr) { + next = curr->next; + internalShrinkCRLtable(curr, 1); + curr = next; + } + psAssert(g_CRL == NULL); +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ +} + +/* Helpers to see if the two CRLs are from the same issuer */ +int32 internalCRLmatch(psX509Crl_t *existing, psX509Crl_t *new) +{ + /* Same DN? */ + if (memcmpct(existing->issuer.hash, new->issuer.hash, SHA1_HASH_SIZE) != 0){ + return -1; + } +#ifdef ENFORCE_CRL_AUTH_KEY_ID_EXT + /* Same AuthKeyId? */ + if (existing->extensions.ak.keyId == NULL || + new->extensions.ak.keyId == NULL) { + /* Should never be possible */ + return PS_PARSE_FAIL; + } + if (existing->extensions.ak.keyLen != new->extensions.ak.keyLen) { + return -1; + } + if (memcmpct(existing->extensions.ak.keyId, new->extensions.ak.keyId, + new->extensions.ak.keyLen) != 0) { + return -1; + } +#endif + /* Looks like a match */ + return PS_TRUE; +} + +/* Remove existing CRL if it exists. Append this one. + FUTURE: Support Delta CRL */ +int psCRL_Update(psX509Crl_t *crl, int deleteExisting) +{ + psX509Crl_t *curr, *next; + int rc; + + if (crl == NULL) { + return 0; + } +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + /* Currently no Delta CRL support so replace the CRL if we find the + same issuer. Add otherwise. */ + curr = g_CRL; + while (curr) { + next = curr->next; + if (internalCRLmatch(curr, crl) == PS_TRUE) { + /* Just do a check to make sure the user isn't trying to update + with the exact same CRL pointer */ + if (curr == crl) { +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + return 0; + } + internalShrinkCRLtable(curr, deleteExisting); + break; + } + curr = next; + } + rc = internalCRLInsert(crl); +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + return rc; +} + +/* Helper to see if we have a matching CRL for the given subject cert. So + this means we are looking at the issuer/authority fields of the cert */ +static int32 internalMatchSubject(psX509Cert_t *cert, psX509Crl_t *CRL) +{ + /* Same DN? */ + if (memcmpct(CRL->issuer.hash, cert->issuer.hash, SHA1_HASH_SIZE) != 0) { + return PS_CERT_AUTH_FAIL_DN; + } +#ifdef ENFORCE_CRL_AUTH_KEY_ID_EXT + /* Same AuthKeyId? */ + if (CRL->extensions.ak.keyId == NULL) { + return PS_CERT_AUTH_FAIL_EXTENSION; + } + if (cert->extensions.ak.keyId == NULL) { + return PS_CERT_AUTH_FAIL_EXTENSION; + } + if (CRL->extensions.ak.keyLen != cert->extensions.ak.keyLen) { + return PS_CERT_AUTH_FAIL_EXTENSION; + } + if (memcmpct(CRL->extensions.ak.keyId, cert->extensions.ak.keyId, + CRL->extensions.ak.keyLen) != 0) { + return PS_CERT_AUTH_FAIL_EXTENSION; + } +#endif + /* Looks good */ + return 1; +} + +/* -1 is exired */ +static int32_t nextUpdateTest(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; + +#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) { + 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); + + if (sysTime.wYear > (int)y) { + 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) +{ + psX509Crl_t *curr; + + if (cert == NULL) { + return NULL; + } + curr = g_CRL; + while (curr) { + if (internalMatchSubject(cert, curr) == PS_TRUE) { + /* This is the point where we want to make sure this CRL isn't + expired. We do this by looking at the nextUpdate time and + seeing if we are beyond that */ + if (nextUpdateTest(curr->nextUpdate, curr->nextUpdateType) < 0) { + /* Got it, but it's expired */ + curr->expired = 1; + } + return curr; + } + curr = curr->next; + } + return NULL; +} + +/* Given a cert, do we have a CRL match for the issuer? + Return if so or NULL if not */ +psX509Crl_t* psCRL_GetCRLForCert(psX509Cert_t *cert) +{ + psX509Crl_t *rc = NULL; +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + rc = internalGetCrlForCert(cert); + +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + return rc; +} + + +/* + -1 no entry in the cache for this cert at all + 0 entry is found and cert is NOT revoked + 1 entry is found and cert IS revoked + + A CRL may be passed in if that specific one is being tested. Otherwise + pass NULL to search the g_CRL +*/ +int32_t internalCrlIsRevoked(psX509Cert_t *cert, psX509Crl_t *CRL) +{ + psX509Crl_t *crl; + x509revoked_t *entry; + + if (cert == NULL) { + return -1; + } + + if (CRL) { + crl = CRL; + } else { + if ((crl = internalGetCrlForCert(cert)) == NULL) { + return -1; + } + } + if (crl->revoked == NULL) { + /* It is totally reasonable to have a CRL with no revoked certs */ + return 0; + } + for (entry = crl->revoked; entry != NULL; entry = entry->next) { + if (cert->serialNumberLen == entry->serialLen) { + if (memcmpct(cert->serialNumber, entry->serial, entry->serialLen) + == 0) { + return 1; /* REVOKED! */ + } + } + } + return 0; /* never found it. good to go */ +} + +/* + Not sure this needs to be public. The "determine" API is actually + doing the full check + + -1 no entry in the cache for this cert at all + 0 entry is found and cert is NOT revoked + 1 entry is found and cert IS revoked + + A CRL may be passed in if that specific one is being tested. Otherwise + pass NULL to search the g_CRL +*/ +int32_t psCRL_isRevoked(psX509Cert_t *cert, psX509Crl_t *CRL) +{ + int32_t rc; +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + rc = internalCrlIsRevoked(cert, CRL); + +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + return rc; +} + +static int doesCertExpectCRL(psX509Cert_t *cert) +{ + if (cert->extensions.crlDist) { + return PS_TRUE; + } + return PS_FALSE; +} + +/* + Uses the psCRL_ format to highlight the use of g_CRL cache + + Updates the "revokedStatus" member of a psX509Cert_t based on information + from within the cert itself and on the revocation status if a g_CRL entry + is found. +*/ +int32_t psCRL_determineRevokedStatus(psX509Cert_t *cert) +{ + psX509Crl_t *crl; + int expectCrl; + int32_t revoked; + + if (cert == NULL) { + return 0; + } +#ifdef USE_MULTITHREADING + psLockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + + crl = internalGetCrlForCert(cert); + + if (crl) { + /* Not going to move along if the CRL has expired */ + if (crl->expired) { + cert->revokedStatus = CRL_CHECK_CRL_EXPIRED; +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + return cert->revokedStatus; + } + + /* If we now have a CRL that is not authenticated yet, let's see if + if our subject happens to have a parent that we can try against. + This case happens if a CRL for an child certificate was + fetched out-of-handshake and now a reconnection attempt is being + made. We now have the parent for that child cert and can + attempt to authenticate */ + if (crl->authenticated == 0 && cert->next) { + psX509AuthenticateCRL(cert->next, crl, NULL); + } + + /* test it and set the status */ + revoked = internalCrlIsRevoked(cert, crl); + if (revoked == 0 && crl->authenticated == 1) { + cert->revokedStatus = CRL_CHECK_PASSED_AND_AUTHENTICATED; + + } else if (revoked == 0 && crl->authenticated == 0) { + cert->revokedStatus = CRL_CHECK_PASSED_BUT_NOT_AUTHENTICATED; + + } else if (revoked == 1 && crl->authenticated == 1) { + cert->revokedStatus = CRL_CHECK_REVOKED_AND_AUTHENTICATED; + + } else if (revoked == 1 && crl->authenticated == 0) { + cert->revokedStatus = CRL_CHECK_REVOKED_BUT_NOT_AUTHENTICATED; + + } else { + psTraceCrypto("Unexpected revoked/authenticated combo\n"); + } + } else { + expectCrl = doesCertExpectCRL(cert); + if (expectCrl) { + cert->revokedStatus = CRL_CHECK_EXPECTED; /* but no entry */ + } else { + cert->revokedStatus = CRL_CHECK_NOT_EXPECTED; + } + } +#ifdef USE_MULTITHREADING + psUnlockMutex(&g_crlTableLock); +#endif /* USE_MULTITHREADING */ + return cert->revokedStatus; +} + +/********************* end of psCRL_ family of APIs ***************************/ + + +/******************************************************************************/ +static void x509FreeRevoked(x509revoked_t **revoked, psPool_t *pool) +{ + x509revoked_t *next, *curr = *revoked; + + while (curr) { + next = curr->next; + psFree(curr->serial, pool); + psFree(curr, pool); + curr = next; + } + *revoked = NULL; +} + +static void internalFreeCRL(psX509Crl_t *crl) +{ + psPool_t *pool; + + if (crl == NULL) { + return; + } + /* test all components for NULL. This is used for freeing during + parse so some might not be there at all */ + pool = crl->pool; + + psX509FreeDNStruct(&crl->issuer, pool); + x509FreeExtensions(&crl->extensions); + x509FreeRevoked(&crl->revoked, pool); + psFree(crl->sig, pool); + psFree(crl->nextUpdate, pool); + + memset(crl, 0, sizeof(psX509Crl_t)); + psFree(crl, pool); +} + +void psX509FreeCRL(psX509Crl_t *crl) +{ + if (crl == NULL) { + return; + } + /* Try to delete from g_CRL list first. Will lock table */ + if (psCRL_Delete(crl)) { + return; + } + internalFreeCRL(crl); +} + + +/* Helper for psX509AuthenticateCRL to see if we have a matching CRL for + the given issuer cert */ +static int32 internalMatchIssuer(psX509Cert_t *CA, psX509Crl_t *CRL) +{ + /* Ensure crlSign flag of KeyUsage for the given CA. */ + if ( ! (CA->extensions.keyUsageFlags & KEY_USAGE_CRL_SIGN)) { + return PS_CERT_AUTH_FAIL_EXTENSION; + } + /* Same DN? */ + if (memcmpct(CRL->issuer.hash, CA->subject.hash, SHA1_HASH_SIZE) != 0) { + psTraceCrypto("CRL not issued by this CA\n"); + return PS_CERT_AUTH_FAIL_DN; + } +#ifdef ENFORCE_CRL_AUTH_KEY_ID_EXT + /* Same AuthKeyId? */ + if (CRL->extensions.ak.keyId == NULL) { + psTraceCrypto("CRL does not have a AuthKeyId extension\n"); + return PS_CERT_AUTH_FAIL_EXTENSION; + } + if (CA->extensions.sk.id == NULL) { + psTraceCrypto("CA does not have a SubjectKeyId extension\n"); + return PS_CERT_AUTH_FAIL_EXTENSION; + } + if (CRL->extensions.ak.keyLen != CA->extensions.sk.len) { + psTraceCrypto("CRL issuer does not have same AuthKeyId as CA\n"); + return PS_CERT_AUTH_FAIL_EXTENSION; + } + if (memcmpct(CRL->extensions.ak.keyId, CA->extensions.sk.id, + CRL->extensions.ak.keyLen) != 0) { + psTraceCrypto("CRL issuer does not have same AuthKeyId as CA\n"); + return PS_CERT_AUTH_FAIL_EXTENSION; + } +#endif + /* Looks good */ + return 1; +} + +/* + NO g_CRL used at all + + Worth noting that the authenticated state is reset each time this is + called so it shouldn't be called blindly in a loop hoping the status + will come out correctly. + + poolUserPtr is for the TMP_PKI pool + */ +int32_t psX509AuthenticateCRL(psX509Cert_t *CA, psX509Crl_t *CRL, + void *poolUserPtr) +{ + int32 rc, sigType; + unsigned char sigOut[SHA512_HASH_SIZE]; + psPool_t *pkiPool = MATRIX_NO_POOL; + + if (CA == NULL || CRL == NULL) { + return PS_ARG_FAIL; + } + if (CRL->authenticated == 1) { + /* Going to have to assume caller knows what they are doing */ + psTraceCrypto("WARNING: this CRL has already been authenticated\n"); + } + CRL->authenticated = 0; + + /* A few tests to see if this CA is the true issuer of the CRL */ + if ((rc = internalMatchIssuer(CA, CRL)) < 0) { + return rc; + } + + /* Determine digest and signature algorithms. */ + switch (CRL->sigAlg) { +#ifdef ENABLE_MD5_SIGNED_CERTS + case OID_MD5_RSA_SIG: + sigType = PS_RSA; + break; +#endif +#ifdef ENABLE_SHA1_SIGNED_CERTS + case OID_SHA1_RSA_SIG: + sigType = PS_RSA; + break; +#ifdef USE_ECC + case OID_SHA1_ECDSA_SIG: + sigType = PS_ECC; + break; +#endif /* USE_ECC */ +#endif /* ENABLE_SHA1_SIGNED_CERTS */ +#ifdef USE_SHA256 + case OID_SHA256_RSA_SIG: + sigType = PS_RSA; + break; +#ifdef USE_ECC + case OID_SHA256_ECDSA_SIG: + sigType = PS_ECC; + break; +#endif /* USE_ECC */ +#endif /* USE_SHA256 */ +#ifdef USE_SHA384 + case OID_SHA384_RSA_SIG: + sigType = PS_RSA; + break; +#ifdef USE_ECC + case OID_SHA384_ECDSA_SIG: + sigType = PS_ECC; + break; +#endif /* USE_ECC */ +#endif /* USE_SHA384 */ +#ifdef USE_SHA512 + case OID_SHA512_RSA_SIG: + sigType = PS_RSA; + break; +#ifdef USE_ECC + case OID_SHA512_ECDSA_SIG: + sigType = PS_ECC; + break; +#endif /* USE_ECC */ +#endif /* USE_SHA512 */ + default: + psTraceCrypto("Need more signature alg support for CRL\n"); + return PS_UNSUPPORTED_FAIL; + } + + /* Perform the signature verification. */ + + if (sigType == PS_RSA) { + rc = pubRsaDecryptSignedElement(pkiPool, &CA->publicKey.key.rsa, + CRL->sig, CRL->sigLen, sigOut, CRL->sigHashLen, NULL); + if (rc < 0) { + psTraceCrypto("Unable to RSA decrypt CRL signature\n"); + return rc; + } + if (memcmpct(CRL->sigHash, sigOut, CRL->sigHashLen) != 0) { + psTraceCrypto("Unable to verify CRL signature\n"); + return PS_CERT_AUTH_FAIL_SIG; + } + } else if (sigType == PS_ECC) { + int32_t status; + rc = psEccDsaVerify(pkiPool, &CA->publicKey.key.ecc, + CRL->sigHash, CRL->sigHashLen, CRL->sig, CRL->sigLen, &status, + NULL); + if (status != 1) { + psTraceCrypto("Unable to verify ECDSA CRL signature\n"); + return PS_CERT_AUTH_FAIL_SIG; + } + } + + CRL->authenticated = PS_TRUE; + + return PS_SUCCESS; +} + + +/* + Parse a CRL. +*/ +int32 psX509ParseCRL(psPool_t *pool, psX509Crl_t **crl, unsigned char *crlBin, + int32 crlBinLen) +{ + const unsigned char *end, *start, *sigStart, *sigEnd, *revStart, *p = crlBin; + int32 oi, version, rc; + x509revoked_t *curr, *next; + psDigestContext_t hashCtx; + psX509Crl_t *lcrl; + uint32_t glen, ilen, tbsCertLen; + uint16_t timelen, plen; + + if (crlBin == NULL || crlBinLen <= 0) { + return PS_ARG_FAIL; + } + end = p + crlBinLen; + /* + CertificateList ::= SEQUENCE { + tbsCertList TBSCertList, + signatureAlgorithm AlgorithmIdentifier, + signatureValue BIT STRING } + + TBSCertList ::= SEQUENCE { + version Version OPTIONAL, + -- if present, shall be v2 + signature AlgorithmIdentifier, + issuer Name, + thisUpdate Time, + nextUpdate Time OPTIONAL, + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, shall be v2 + } OPTIONAL, + crlExtensions [0] EXPLICIT Extensions OPTIONAL + -- if present, shall be v2 + } + */ + if (getAsnSequence32(&p, (uint32)(end - p), &glen, 0) < 0) { + psTraceCrypto("Initial parse error in psX509ParseCRL\n"); + return PS_PARSE_FAIL; + } + + /* Track tbsCert for signature purposes and for encoding where there + is no revokedCertificate entry */ + sigStart = p; + if (getAsnSequence32(&p, (uint32)(end - p), &tbsCertLen, 0) < 0) { + psTraceCrypto("Initial parse error in psX509ParseCRL\n"); + return PS_PARSE_FAIL; + } + start = p; + if (*p == ASN_INTEGER) { + version = 0; + if (getAsnInteger(&p, (uint32)(end - p), &version) < 0 || version != 1){ + psTraceIntCrypto("Version parse error in psX509ParseCRL %d\n", + version); + return PS_PARSE_FAIL; + } + } + + /* looking correct. Allocate the psX509Crl_t */ + if ((lcrl = psMalloc(pool, sizeof(psX509Crl_t))) == NULL) { + return PS_MEM_FAIL; + } + memset(lcrl, 0, sizeof(psX509Crl_t)); + lcrl->pool = pool; + + /* signature */ + if (getAsnAlgorithmIdentifier(&p, (int32)(end - p), &lcrl->sigAlg, &plen) + < 0) { + psTraceCrypto("Couldn't parse crl sig algorithm identifier\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + + /* + Name ::= CHOICE { -- only one possibility for now -- + rdnSequence RDNSequence } + + RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + + DistinguishedName ::= RDNSequence + + RelativeDistinguishedName ::= + SET SIZE (1 .. MAX) OF AttributeTypeAndValue + */ + if ((rc = psX509GetDNAttributes(pool, &p, (uint32)(end - p), + &lcrl->issuer, 0)) < 0) { + psX509FreeCRL(lcrl); + psTraceCrypto("Couldn't parse crl issuer DN attributes\n"); + return rc; + } + + /* thisUpdate TIME */ + if ((end - p) < 1 || ((*p != ASN_UTCTIME) && (*p != ASN_GENERALIZEDTIME))) { + psTraceCrypto("Malformed thisUpdate CRL\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + p++; + if (getAsnLength(&p, (uint32)(end - p), &timelen) < 0 || + (uint32)(end - p) < timelen) { + psTraceCrypto("Malformed thisUpdate CRL\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + p += timelen; /* Skip it. Only concerned with expiration */ + /* nextUpdateTIME - Optional... but required by spec */ + if ((end - p) < 1 || ((*p == ASN_UTCTIME) || (*p == ASN_GENERALIZEDTIME))) { + lcrl->nextUpdateType = *p; + p++; + if (getAsnLength(&p, (uint32)(end - p), &timelen) < 0 || + (uint32)(end - p) < timelen) { + psTraceCrypto("Malformed nextUpdateTIME CRL\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + if ((lcrl->nextUpdate = psMalloc(pool, timelen + 1)) == NULL) { + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + memcpy(lcrl->nextUpdate, p, timelen); + lcrl->nextUpdate[timelen] = '\0'; + p += timelen; + + /* TODO: Confirm here if this is already expired */ + } + + + /* Need to see if any data left in tbsCertList. Could be no revocations */ + if ((p - start) != tbsCertLen) { + /* + revokedCertificates SEQUENCE OF SEQUENCE { + userCertificate CertificateSerialNumber, + revocationDate Time, + crlEntryExtensions Extensions OPTIONAL + -- if present, shall be v2 + } OPTIONAL, + */ + + /* Need to peek at next byte to make sure there are some revoked + certs here. Could be jumping right to crlExtensions */ + if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0)) { + + if (getAsnSequence32(&p, (uint32)(end - p), &glen, 0) < 0) { + psTraceCrypto("Initial revokedCert error in psX509ParseCRL\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + + lcrl->revoked = curr = psMalloc(pool, sizeof(x509revoked_t)); + if (curr == NULL) { + psX509FreeCRL(lcrl); + return PS_MEM_FAIL; + } + memset(curr, 0x0, sizeof(x509revoked_t)); + while (glen > 0) { + revStart = p; + if (getAsnSequence32(&p, (uint32)(end - p), &ilen, 0) < 0) { + psTraceCrypto("Deep revokedCert error in psX509ParseCRL\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + start = p; /* reusing start */ + if ((rc = getSerialNum(pool, &p, ilen, &curr->serial, + &curr->serialLen)) < 0) { + psTraceCrypto("ASN serial number parse error\n"); + psX509FreeCRL(lcrl); + return rc; + } + /* skipping time and crlEntryExtensions */ + p += ilen - (uint32)(p - start); + if (glen < (uint32)(p - revStart)) { + psTraceCrypto("Deeper revokedCert err in psX509ParseCRL\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + glen -= (uint32)(p - revStart); + + // psTraceBytes("revoked", curr->serial, curr->serialLen); + if (glen > 0) { + if ((next = psMalloc(pool, sizeof(x509revoked_t))) == NULL){ + psX509FreeCRL(lcrl); + return PS_MEM_FAIL; + } + memset(next, 0x0, sizeof(x509revoked_t)); + curr->next = next; + curr = next; + } + } + } + /* Always treated as OPTIONAL */ + if (getExplicitExtensions(pool, &p, (uint32)(end - p), 0, + &lcrl->extensions, 0) < 0) { + psTraceCrypto("Extension parse error in psX509ParseCRL\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + //if (lcrl->extensions.ak.keyId) { + // psTraceBytes("CRL ak", lcrl->extensions.ak.keyId, 20); + //} + } /* End tbsCertList */ + sigEnd = p; + + if (getAsnAlgorithmIdentifier(&p, (int32)(end - p), &oi, &plen) < 0) { + psX509FreeCRL(lcrl); + psTraceCrypto("Couldn't parse crl sig algorithm identifier\n"); + return PS_PARSE_FAIL; + } + /* must match */ + if (oi != lcrl->sigAlg) { + psTraceCrypto("Couldn't match crl sig algorithm identifier\n"); + psX509FreeCRL(lcrl); + return PS_PARSE_FAIL; + } + + if ((rc = psX509GetSignature(pool, &p, (uint32)(end - p), &lcrl->sig, + &lcrl->sigLen)) < 0) { + psX509FreeCRL(lcrl); + psTraceCrypto("Couldn't parse signature\n"); + return rc; + } + + /* Perform the hashing for later auth */ + switch (lcrl->sigAlg) { +#ifdef ENABLE_MD5_SIGNED_CERTS + case OID_MD5_RSA_SIG: + lcrl->sigHashLen = MD5_HASH_SIZE; + break; +#endif +#ifdef ENABLE_SHA1_SIGNED_CERTS + case OID_SHA1_RSA_SIG: + lcrl->sigHashLen = SHA1_HASH_SIZE; + break; +#ifdef USE_ECC + case OID_SHA1_ECDSA_SIG: + lcrl->sigHashLen = SHA1_HASH_SIZE; + break; +#endif /* USE_ECC */ +#endif /* ENABLE_SHA1_SIGNED_CERTS */ +#ifdef USE_SHA256 + case OID_SHA256_RSA_SIG: + lcrl->sigHashLen = SHA256_HASH_SIZE; + break; +#ifdef USE_ECC + case OID_SHA256_ECDSA_SIG: + lcrl->sigHashLen = SHA256_HASH_SIZE; + break; +#endif /* USE_ECC */ +#endif /* USE_SHA256 */ +#ifdef USE_SHA384 + case OID_SHA384_RSA_SIG: + lcrl->sigHashLen = SHA384_HASH_SIZE; + break; +#ifdef USE_ECC + case OID_SHA384_ECDSA_SIG: + lcrl->sigHashLen = SHA384_HASH_SIZE; + break; +#endif /* USE_ECC */ +#endif /* USE_SHA384 */ +#ifdef USE_SHA512 + case OID_SHA512_RSA_SIG: + lcrl->sigHashLen = SHA512_HASH_SIZE; + break; +#ifdef USE_ECC + case OID_SHA512_ECDSA_SIG: + lcrl->sigHashLen = SHA512_HASH_SIZE; + break; +#endif /* USE_ECC */ +#endif /* USE_SHA512 */ + default: + psX509FreeCRL(lcrl); + psTraceCrypto("Need more signature alg support for CRL\n"); + return PS_UNSUPPORTED_FAIL; + } + + switch(lcrl->sigHashLen) { +#ifdef ENABLE_MD5_SIGNED_CERTS + case MD5_HASH_SIZE: + psMd5Init(&hashCtx.md5); + psMd5Update(&hashCtx.md5, sigStart, (uint32)(sigEnd - sigStart)); + psMd5Final(&hashCtx.md5, lcrl->sigHash); + break; +#endif /* ENABLE_MD5_SIGNED_CERTS */ +#ifdef ENABLE_SHA1_SIGNED_CERTS + case SHA1_HASH_SIZE: + psSha1Init(&hashCtx.sha1); + psSha1Update(&hashCtx.sha1, sigStart, (uint32)(sigEnd - sigStart)); + psSha1Final(&hashCtx.sha1, lcrl->sigHash); + break; +#endif /* ENABLE_SHA1_SIGNED_CERTS */ +#ifdef USE_SHA256 + case SHA256_HASH_SIZE: + psSha256Init(&hashCtx.sha256); + psSha256Update(&hashCtx.sha256, sigStart, (uint32)(sigEnd - sigStart)); + psSha256Final(&hashCtx.sha256, lcrl->sigHash); + break; +#endif /* USE_SHA256 */ +#ifdef USE_SHA384 + case SHA384_HASH_SIZE: + psSha384Init(&hashCtx.sha384); + psSha384Update(&hashCtx.sha384, sigStart, (uint32)(sigEnd - sigStart)); + psSha384Final(&hashCtx.sha384, lcrl->sigHash); + break; +#endif /* USE_SHA384 */ +#ifdef USE_SHA512 + case SHA512_HASH_SIZE: + psSha512Init(&hashCtx.sha512); + psSha512Update(&hashCtx.sha512, sigStart, (uint32)(sigEnd - sigStart)); + psSha512Final(&hashCtx.sha512, lcrl->sigHash); + break; +#endif /* USE_SHA512 */ + default: + psX509FreeCRL(lcrl); + psTraceCrypto("Unsupported digest algorithm in CRL\n"); + return PS_UNSUPPORTED_FAIL; + } + + *crl = lcrl; + + return PS_SUCCESS; +} + +/* + If the provided cert has a URL based CRL Distribution point, return + that. The url and urlLen point directly into the cert structure so + must not be modified. + + TODO: This should return all URL dist points in the cert. Not just first +*/ +int32 psX509GetCRLdistURL(psX509Cert_t *cert, char **url, uint32_t *urlLen) +{ + x509GeneralName_t *gn; + + if (cert == NULL) { + return PS_ARG_FAIL; + } + *url = NULL; + *urlLen = 0; + + if (cert->extensions.crlDist != NULL) { + gn = cert->extensions.crlDist; + while (gn) { + if (gn->id == 6) { /* Only pass on URI types */ + *url = (char*)gn->data; + *urlLen = gn->dataLen; + return PS_TRUE; + } else { + psTraceIntCrypto("Unsupported CRL distro point format %d\n", + gn->id); + } + gn = gn->next; + } + } + return PS_FALSE; +} + +/******************************************************************************/ + +#endif /* USE_CERT_PARSE */ +#endif /* USE_CRL */ + diff --git a/crypto/keyformat/pkcs.c b/crypto/keyformat/pkcs.c index 872f97a..aac3b02 100644 --- a/crypto/keyformat/pkcs.c +++ b/crypto/keyformat/pkcs.c @@ -1391,6 +1391,47 @@ static int32 hexToBinary(unsigned char *hex, unsigned char *bin, int32 binlen) #endif /* USE_PKCS5 */ #ifdef USE_RSA +int32_t pkcs1ParsePubFile(psPool_t *pool, const char *fileName, psRsaKey_t *key) +{ + unsigned char *DERout; + unsigned char sha1KeyHash[SHA1_HASH_SIZE]; + const unsigned char *p, *end; + int32_t rc, oi; + uint16_t DERlen, seqlen, plen; + + /* Had to tweak pkcs1DecodePrivFile to accept PUBLIC KEY headers */ + if ((rc = pkcs1DecodePrivFile(pool, fileName, NULL, &DERout, &DERlen)) + < PS_SUCCESS) { + return rc; + } + + p = DERout; + end = p + DERlen; + + if (getAsnSequence(&p, (int32)(end - p), &seqlen) < 0) { + psTraceCrypto("Couldn't parse PKCS#1 RSA public key file\n"); + goto pubKeyFail; + } + if (getAsnAlgorithmIdentifier(&p, (int32)(end - p), &oi, &plen) < 0) { + psTraceCrypto("Couldn't parse PKCS#1 RSA public key file\n"); + goto pubKeyFail; + } + if (oi != OID_RSA_KEY_ALG) { + psTraceCrypto("Couldn't parse PKCS#1 RSA public key file\n"); + goto pubKeyFail; + } + if (psRsaParseAsnPubKey(pool, &p,(int32)(end - p), key, sha1KeyHash) < 0) { + psTraceCrypto("Couldn't parse PKCS#1 RSA public key file\n"); + goto pubKeyFail; + } + + psFree(DERout, pool); + return PS_SUCCESS; + +pubKeyFail: + psFree(DERout, pool); + return PS_PARSE_FAIL; +} /******************************************************************************/ /** Parse a PEM format private key file. @@ -1480,6 +1521,15 @@ int32_t pkcs1DecodePrivFile(psPool_t *pool, const char *fileName, start++; } PEMlen = (uint32)(end - start); + } else if (((start = strstr((char*)keyBuf, "-----BEGIN")) != NULL) && + ((start = strstr((char*)keyBuf, "PUBLIC KEY-----")) != NULL) && + ((end = strstr(start, "-----END")) != NULL) && + ((endTmp = strstr(end, "PUBLIC KEY-----")) != NULL)) { + start += strlen("PUBLIC KEY-----"); + while (*start == '\x0d' || *start == '\x0a') { + start++; + } + PEMlen = (uint32)(end - start); } else { psTraceCrypto("File buffer does not look to be in PKCS#1 PEM format\n"); psFree(keyBuf, pool); diff --git a/crypto/keyformat/x509.c b/crypto/keyformat/x509.c index 44ff817..dfca460 100644 --- a/crypto/keyformat/x509.c +++ b/crypto/keyformat/x509.c @@ -104,6 +104,8 @@ static const struct { OID_LIST(id_ce, id_ce_policyConstraints), OID_LIST(id_ce, id_ce_extKeyUsage), OID_LIST(id_ce, id_ce_cRLDistributionPoints), + OID_LIST(id_ce, id_ce_cRLNumber), + OID_LIST(id_ce, id_ce_issuingDistributionPoint), OID_LIST(id_ce, id_ce_inhibitAnyPolicy), OID_LIST(id_ce, id_ce_freshestCRL), OID_LIST(id_pe, id_pe_authorityInfoAccess), @@ -141,10 +143,6 @@ static int32_t x509ConfirmSignature(const unsigned char *sigHash, const unsigned char *sigOut, uint16_t sigLen); #endif -#ifdef USE_CRL -static void x509FreeRevoked(x509revoked_t **revoked); -#endif - #endif /* USE_CERT_PARSE */ /******************************************************************************/ @@ -1011,6 +1009,9 @@ void x509FreeExtensions(x509v3extensions_t *extensions) x509GeneralName_t *active, *inc; + if (extensions == NULL) { + return; + } if (extensions->san) { active = extensions->san; while (active != NULL) { @@ -1022,6 +1023,9 @@ void x509FreeExtensions(x509v3extensions_t *extensions) } #ifdef USE_CRL + if (extensions->crlNum) { + psFree(extensions->crlNum, extensions->pool); + } if (extensions->crlDist) { active = extensions->crlDist; while (active != NULL) { @@ -1099,7 +1103,7 @@ void psX509FreeCert(psX509Cert_t *cert) if (curr->uniqueSubjectId) psFree(curr->uniqueSubjectId, pool); - if (curr->publicKey.type != PS_NONE) { + if (curr->publicKey.type != PS_NOKEY) { switch (curr->pubKeyAlgorithm) { #ifdef USE_RSA case OID_RSA_KEY_ALG: @@ -1116,13 +1120,10 @@ void psX509FreeCert(psX509Cert_t *cert) psAssert(0); break; } - curr->publicKey.type = PS_NONE; + curr->publicKey.type = PS_NOKEY; } x509FreeExtensions(&curr->extensions); -#ifdef USE_CRL - x509FreeRevoked(&curr->revoked); -#endif #endif /* USE_CERT_PARSE */ next = curr->next; psFree(curr, pool); @@ -1546,7 +1547,7 @@ static void psTraceOid(uint32_t oid[MAX_OID_LEN], uint8_t oidlen) found = 0; for (j = 0; oid_list[j].oid[0] != 0 && !found; j++) { for (i = 0; i < oidlen; i++) { - if ((uint8_t)(oid[i] & 0xFF) != oid_list[j].oid[i]) { + if ((uint16_t)(oid[i] & 0xFFFF) != oid_list[j].oid[i]) { break; } if ((i + 1) == oidlen) { @@ -1924,8 +1925,26 @@ KNOWN_EXT: break; #ifdef USE_CRL + case OID_ENUM(id_ce_cRLNumber): + /* A required extension within a CRL. Our getSerialNum is + the version of getInteger that allows very large + numbers. Spec says this could be 20 octets long */ + if (getSerialNum(pool, &p, (int32)(extEnd - p), + &(extensions->crlNum), &len) < 0) { + psTraceCrypto("Error parsing ak.serialNum\n"); + return PS_PARSE_FAIL; + } + extensions->crlNumLen = len; + break; + + case OID_ENUM(id_ce_issuingDistributionPoint): + /* RFC 3280 - Although the extension is critical, conforming + implementations are not required to support this extension. */ + p++; + p = p + (fullExtLen - (p - extStart)); + break; + case OID_ENUM(id_ce_cRLDistributionPoints): - if (getAsnSequence(&p, (int32)(extEnd - p), &fullExtLen) < 0) { psTraceCrypto("Error parsing authKeyId extension\n"); return PS_PARSE_FAIL; @@ -2310,22 +2329,74 @@ static int32 issuedBefore(rfc_e rfc, const psX509Cert_t *cert) } /******************************************************************************/ +/** + 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 Returns - 0 on success - PS_CERT_AUTH_FAIL_DATE if date is out of range + 0 on parse success (FAIL_DATE_FLAG could be set) PS_FAILURE on parse error */ static int32 validateDateRange(psX509Cert_t *cert) { + unsigned int y; + unsigned short m, d; + #ifdef POSIX struct tm t; time_t rawtime; - unsigned char *c; - unsigned int y; - unsigned short m, d; + time(&rawtime); localtime_r(&rawtime, &t); @@ -2333,35 +2404,10 @@ static int32 validateDateRange(psX509Cert_t *cert) t.tm_mon++; t.tm_year += 1900; - /* 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,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) { + if (getDateComponents(cert, 0, &y, &m, &d) < 0) { return PS_FAILURE; } + if (t.tm_year < (int)y) { cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; } else if (t.tm_year == (int)y) { @@ -2372,33 +2418,7 @@ static int32 validateDateRange(psX509Cert_t *cert) } } - /* Validate the 'not after' date */ - if ((c = (unsigned char *)cert->notAfter) == NULL) { - return PS_FAILURE; - } - /* UTCTIME, defined in 1982, has just a 2 digit year */ - /* year as unsigned int handles over/underflows */ - if (cert->notAfterTimeType == 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) { + if (getDateComponents(cert, 1, &y, &m, &d) < 0) { return PS_FAILURE; } if (t.tm_year > (int)y) { @@ -2412,17 +2432,51 @@ static int32 validateDateRange(psX509Cert_t *cert) } return 0; #else -/* Warn if we are skipping the date validation checks. */ + #ifdef WIN32 -#pragma message("CERTIFICATE DATE VALIDITY NOT SUPPORTED ON THIS PLATFORM.") + + 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." -#endif cert->authFailFlags |= PS_CERT_AUTH_FAIL_DATE_FLAG; return 0; +#endif /* WIN32 */ #endif /* POSIX */ } + /******************************************************************************/ /* Implementation specific date parser. Does not actually verify the date @@ -2858,9 +2912,6 @@ int32 psX509AuthenticateCert(psPool_t *pool, psX509Cert_t *subjectCert, unsigned char *tempSig = NULL; #endif /* USE_RSA */ psPool_t *pkiPool = NULL; -#ifdef USE_CRL - x509revoked_t *curr, *next; -#endif #ifdef USE_PKCS1_PSS uint16_t pssLen; #endif @@ -2925,22 +2976,13 @@ int32 psX509AuthenticateCert(psPool_t *pool, psX509Cert_t *subjectCert, } #ifdef USE_CRL - /* Does this issuer have a list of revoked serial numbers that needs - to be checked? */ - if (ic->revoked) { - curr = ic->revoked; - while (curr != NULL) { - next = curr->next; - if (curr->serialLen == sc->serialNumberLen) { - if (memcmp(curr->serial, sc->serialNumber, curr->serialLen) - == 0) { - sc->authStatus = PS_CERT_AUTH_FAIL_REVOKED; - return -1; - } - } - curr = next; - } - + /* This function operates on the global cache */ + psCRL_determineRevokedStatus(sc); + /* The only status that is going to make us terminate the connection + immediately is if we find REVOKED_AND_AUTHENTICATED */ + if (sc->revokedStatus == CRL_CHECK_REVOKED_AND_AUTHENTICATED) { + sc->authStatus = PS_CERT_AUTH_FAIL_REVOKED; + return PS_CERT_AUTH_FAIL_REVOKED; } #endif @@ -3332,297 +3374,9 @@ static int32_t x509ConfirmSignature(const unsigned char *sigHash, return PS_SUCCESS; } #endif /* USE_RSA */ - /******************************************************************************/ -#ifdef USE_CRL -static void x509FreeRevoked(x509revoked_t **revoked) -{ - x509revoked_t *next, *curr = *revoked; - - while (curr) { - next = curr->next; - psFree(curr->serial, curr->pool); - psFree(curr, curr->pool); - curr = next; - } - *revoked = NULL; -} - -/* - Parse a CRL and confirm was issued by supplied CA. - - Only interested in the revoked serial numbers which are stored in the - CA structure if all checks out. Used during cert validation as part of - the default tests - - poolUserPtr is for the TMP_PKI pool -*/ -int32 psX509ParseCrl(psPool_t *pool, psX509Cert_t *CA, int append, - unsigned char *crlBin, int32 crlBinLen, - void *poolUserPtr) -{ - unsigned char *end, *start, *revStart, *sigStart, *sigEnd,*p = crlBin; - int32 oi, plen, sigLen, version, rc; - unsigned char sigHash[SHA512_HASH_SIZE], sigOut[SHA512_HASH_SIZE]; - x509revoked_t *curr, *next; - x509DNattributes_t issuer; - x509v3extensions_t ext; - psDigestContext_t hashCtx; - psPool_t *pkiPool = MATRIX_NO_POOL; - uint16_t glen, ilen, timelen; - - end = p + crlBinLen; - /* - CertificateList ::= SEQUENCE { - tbsCertList TBSCertList, - signatureAlgorithm AlgorithmIdentifier, - signatureValue BIT STRING } - - TBSCertList ::= SEQUENCE { - version Version OPTIONAL, - -- if present, shall be v2 - signature AlgorithmIdentifier, - issuer Name, - thisUpdate Time, - nextUpdate Time OPTIONAL, - revokedCertificates SEQUENCE OF SEQUENCE { - userCertificate CertificateSerialNumber, - revocationDate Time, - crlEntryExtensions Extensions OPTIONAL - -- if present, shall be v2 - } OPTIONAL, - crlExtensions [0] EXPLICIT Extensions OPTIONAL - -- if present, shall be v2 - } - */ - if (getAsnSequence(&p, (uint32)(end - p), &glen) < 0) { - psTraceCrypto("Initial parse error in psX509ParseCrl\n"); - return PS_PARSE_FAIL; - } - - sigStart = p; - if (getAsnSequence(&p, (uint32)(end - p), &glen) < 0) { - psTraceCrypto("Initial parse error in psX509ParseCrl\n"); - return PS_PARSE_FAIL; - } - if (*p == ASN_INTEGER) { - version = 0; - if (getAsnInteger(&p, (uint32)(end - p), &version) < 0 || version != 1){ - psTraceIntCrypto("Version parse error in psX509ParseCrl %d\n", - version); - return PS_PARSE_FAIL; - } - } - /* signature */ - if (getAsnAlgorithmIdentifier(&p, (int32)(end - p), &oi, &plen) < 0) { - psTraceCrypto("Couldn't parse crl sig algorithm identifier\n"); - return PS_PARSE_FAIL; - } - - /* - Name ::= CHOICE { -- only one possibility for now -- - rdnSequence RDNSequence } - - RDNSequence ::= SEQUENCE OF RelativeDistinguishedName - - DistinguishedName ::= RDNSequence - - RelativeDistinguishedName ::= - SET SIZE (1 .. MAX) OF AttributeTypeAndValue - */ - memset(&issuer, 0x0, sizeof(x509DNattributes_t)); - if ((rc = psX509GetDNAttributes(pool, &p, (uint32)(end - p), - &issuer, 0)) < 0) { - psTraceCrypto("Couldn't parse crl issuer DN attributes\n"); - return rc; - } - /* Ensure crlSign flag of KeyUsage for the given CA. */ - if ( ! (CA->extensions.keyUsageFlags & KEY_USAGE_CRL_SIGN)) { - psTraceCrypto("Issuer does not allow crlSign in keyUsage\n"); - CA->authFailFlags |= PS_CERT_AUTH_FAIL_KEY_USAGE_FLAG; - CA->authStatus = PS_CERT_AUTH_FAIL_EXTENSION; - psX509FreeDNStruct(&issuer, pool); - return PS_CERT_AUTH_FAIL_EXTENSION; - } - if (memcmp(issuer.hash, CA->subject.hash, SHA1_HASH_SIZE) != 0) { - psTraceCrypto("CRL NOT ISSUED BY THIS CA\n"); - psX509FreeDNStruct(&issuer, pool); - return PS_CERT_AUTH_FAIL_DN; - } - psX509FreeDNStruct(&issuer, pool); - - /* thisUpdate TIME */ - if ((end - p) < 1 || ((*p != ASN_UTCTIME) && (*p != ASN_GENERALIZEDTIME))) { - psTraceCrypto("Malformed thisUpdate CRL\n"); - return PS_PARSE_FAIL; - } - p++; - if (getAsnLength(&p, (uint32)(end - p), &timelen) < 0 || - (uint32)(end - p) < timelen) { - psTraceCrypto("Malformed thisUpdate CRL\n"); - return PS_PARSE_FAIL; - } - p += timelen; /* Skip it */ - /* nextUpdateTIME - Optional */ - if ((end - p) < 1 || ((*p == ASN_UTCTIME) || (*p == ASN_GENERALIZEDTIME))) { - p++; - if (getAsnLength(&p, (uint32)(end - p), &timelen) < 0 || - (uint32)(end - p) < timelen) { - psTraceCrypto("Malformed nextUpdateTIME CRL\n"); - return PS_PARSE_FAIL; - } - p += timelen; /* Skip it */ - } - /* - revokedCertificates SEQUENCE OF SEQUENCE { - userCertificate CertificateSerialNumber, - revocationDate Time, - crlEntryExtensions Extensions OPTIONAL - -- if present, shall be v2 - } OPTIONAL, - */ - if (getAsnSequence(&p, (uint32)(end - p), &glen) < 0) { - psTraceCrypto("Initial revokedCertificates error in psX509ParseCrl\n"); - return PS_PARSE_FAIL; - } - - if (CA->revoked) { - /* Append or refresh */ - if (append == 0) { - /* refresh */ - x509FreeRevoked(&CA->revoked); - CA->revoked = curr = psMalloc(pool, sizeof(x509revoked_t)); - if (curr == NULL) { - return PS_MEM_FAIL; - } - } else { - /* append. not looking for duplicates */ - curr = psMalloc(pool, sizeof(x509revoked_t)); - if (curr == NULL) { - return PS_MEM_FAIL; - } - curr->pool = pool; - next = CA->revoked; - while (next->next != NULL) { - next = next->next; - } - next->next = curr; - } - } else { - CA->revoked = curr = psMalloc(pool, sizeof(x509revoked_t)); - if (curr == NULL) { - return PS_MEM_FAIL; - } - } - memset(curr, 0x0, sizeof(x509revoked_t)); - curr->pool = pool; - - - while (glen > 0) { - revStart = p; - if (getAsnSequence(&p, (uint32)(end - p), &ilen) < 0) { - psTraceCrypto("Deep revokedCertificates error in psX509ParseCrl\n"); - return PS_PARSE_FAIL; - } - start = p; - if ((rc = getSerialNum(pool, &p, (uint32)(end - p), &curr->serial, - &curr->serialLen)) < 0) { - psTraceCrypto("ASN serial number parse error\n"); - return rc; - } - /* skipping time and extensions */ - p += ilen - (uint32)(p - start); - if (glen < (uint32)(p - revStart)) { - psTraceCrypto("Deeper revokedCertificates err in psX509ParseCrl\n"); - return PS_PARSE_FAIL; - } - glen -= (uint32)(p - revStart); - - // psTraceBytes("revoked", curr->serial, curr->serialLen); - if (glen > 0) { - if ((next = psMalloc(pool, sizeof(x509revoked_t))) == NULL) { - x509FreeRevoked(&CA->revoked); - return PS_MEM_FAIL; - } - memset(next, 0x0, sizeof(x509revoked_t)); - next->pool = pool; - curr->next = next; - curr = next; - } - } - memset(&ext, 0x0, sizeof(x509v3extensions_t)); - if (getExplicitExtensions(pool, &p, (uint32)(end - p), 0, &ext, 0) < 0) { - psTraceCrypto("Extension parse error in psX509ParseCrl\n"); - x509FreeRevoked(&CA->revoked); - return PS_PARSE_FAIL; - } - x509FreeExtensions(&ext); - sigEnd = p; - - if (getAsnAlgorithmIdentifier(&p, (int32)(end - p), &oi, &plen) < 0) { - x509FreeRevoked(&CA->revoked); - psTraceCrypto("Couldn't parse crl sig algorithm identifier\n"); - return PS_PARSE_FAIL; - } - - if ((rc = psX509GetSignature(pool, &p, (uint32)(end - p), &revStart, &ilen)) - < 0) { - x509FreeRevoked(&CA->revoked); - psTraceCrypto("Couldn't parse signature\n"); - return rc; - } - - switch (oi) { -#ifdef ENABLE_MD5_SIGNED_CERTS - case OID_MD5_RSA_SIG: - sigLen = MD5_HASH_SIZE; - psMd5Init(&hashCtx); - psMd5Update(&hashCtx, sigStart, (uint32)(sigEnd - sigStart)); - psMd5Final(&hashCtx, sigHash); - break; -#endif -#ifdef ENABLE_SHA1_SIGNED_CERTS - case OID_SHA1_RSA_SIG: - sigLen = SHA1_HASH_SIZE; - psSha1Init(&hashCtx); - psSha1Update(&hashCtx, sigStart, (uint32)(sigEnd - sigStart)); - psSha1Final(&hashCtx, sigHash); - break; -#endif -#ifdef USE_SHA256 - case OID_SHA256_RSA_SIG: - sigLen = SHA256_HASH_SIZE; - psSha256Init(&hashCtx); - psSha256Update(&hashCtx, sigStart, (uint32)(sigEnd - sigStart)); - psSha256Final(&hashCtx, sigHash); - break; -#endif - default: - psTraceCrypto("Need more signatuare alg support for CRL\n"); - x509FreeRevoked(&CA->revoked); - return PS_UNSUPPORTED_FAIL; - } - - - if ((rc = pubRsaDecryptSignedElement(pkiPool, &CA->publicKey.key.rsa, - revStart, ilen, sigOut, sigLen, NULL)) < 0) { - x509FreeRevoked(&CA->revoked); - psTraceCrypto("Unable to RSA decrypt CRL signature\n"); - return rc; - } - - if (memcmp(sigHash, sigOut, sigLen) != 0) { - x509FreeRevoked(&CA->revoked); - psTraceCrypto("Unable to verify CRL signature\n"); - return PS_CERT_AUTH_FAIL_SIG; - } - - return PS_SUCCESS; -} -#endif /* USE_CRL */ #endif /* USE_CERT_PARSE */ - #ifdef USE_OCSP static int32_t parseSingleResponse(uint32_t len, const unsigned char **cp, const unsigned char *end, mOCSPSingleResponse_t *res) @@ -4315,6 +4069,12 @@ int32_t validateOCSPResponse(psPool_t *pool, psX509Cert_t *trustedOCSP, return PS_FAILURE; } +#if 0 /* The issuer here is pointing to the cert that signed the OCSPRespose + and that is not necessarily the parent of the subject cert we + are looking at. If we want to include this test, we'd need to + find the issuer of the subject and look at the KeyHash as + an additional verification */ + /* Issuer portion of the validation - the subject cert issuer key and name hash should match what the subjectResponse reports @@ -4336,6 +4096,8 @@ int32_t validateOCSPResponse(psPool_t *pool, psX509Cert_t *trustedOCSP, return PS_FAILURE; } } +#endif /* 0 */ + /* Finally do the sig validation */ switch (response->sigAlg) { diff --git a/crypto/keyformat/x509.h b/crypto/keyformat/x509.h index bc0910f..8744512 100644 --- a/crypto/keyformat/x509.h +++ b/crypto/keyformat/x509.h @@ -173,6 +173,8 @@ enum { id_ce_issuerAltName = 18, id_ce_subjectDirectoryAttributes = 9, id_ce_basicConstraints = 19, + id_ce_cRLNumber = 20, + id_ce_issuingDistributionPoint = 28, id_ce_nameConstraints = 30, id_ce_policyConstraints = 36, id_ce_extKeyUsage = 37, @@ -264,6 +266,8 @@ typedef enum { OID_ENUM(id_ce_policyConstraints), OID_ENUM(id_ce_extKeyUsage), OID_ENUM(id_ce_cRLDistributionPoints), + OID_ENUM(id_ce_cRLNumber), + OID_ENUM(id_ce_issuingDistributionPoint), OID_ENUM(id_ce_inhibitAnyPolicy), OID_ENUM(id_ce_freshestCRL), OID_ENUM(id_pe_authorityInfoAccess), @@ -319,6 +323,8 @@ typedef struct { #endif /* USE_FULL_CERT_PARSE */ #ifdef USE_CRL x509GeneralName_t *crlDist; + unsigned char *crlNum; + int32 crlNumLen; #endif } x509v3extensions_t; @@ -326,11 +332,27 @@ typedef struct { #ifdef USE_CRL typedef struct x509revoked { - psPool_t *pool; unsigned char *serial; uint16_t serialLen; struct x509revoked *next; } x509revoked_t; + +typedef struct psCRL { + psPool_t *pool; + int32_t authenticated; /* Has this CRL been authenticated */ + unsigned char sigHash[MAX_HASH_SIZE]; + int32_t sigHashLen; + int32 nextUpdateType; + char *nextUpdate; /* Only concerned about expiration */ + int32_t sigAlg; /* OID_SHA1_RSA_SIG */ + unsigned char *sig; + uint16_t sigLen; + uint16_t expired; + x509DNattributes_t issuer; + x509v3extensions_t extensions; + x509revoked_t *revoked; + struct psCRL *next; +} psX509Crl_t; #endif @@ -366,8 +388,8 @@ typedef struct psCert { x509v3extensions_t extensions; int32 authStatus; /* See psX509AuthenticateCert doc */ uint32 authFailFlags; /* Flags for extension check failures */ -#ifdef USE_CRL - x509revoked_t *revoked; +#ifdef USE_CRL /* Use for OCSP later as well? */ + int32 revokedStatus; #endif unsigned char sigHash[MAX_HASH_SIZE]; #endif /* USE_CERT_PARSE */ @@ -434,6 +456,9 @@ extern int32_t parseOCSPResponse(psPool_t *pool, int32_t len, mOCSPResponse_t *response); extern int32_t validateOCSPResponse(psPool_t *pool, psX509Cert_t *trustedOCSP, psX509Cert_t *srvCerts, mOCSPResponse_t *response); +extern int32_t matrixSslWriteOCSPRequest(psPool_t *pool, psX509Cert_t *cert, + psX509Cert_t *certIssuer, unsigned char **request, + uint32_t *requestLen, int32_t flags); #endif /******************************************************************************/ diff --git a/crypto/layer/matrix.c b/crypto/layer/matrix.c index 2a9218c..426f999 100644 --- a/crypto/layer/matrix.c +++ b/crypto/layer/matrix.c @@ -64,6 +64,9 @@ int32_t psCryptoOpen(const char *config) return PS_FAILURE; } psOpenPrng(); +#ifdef USE_CRL + psCrlOpen(); +#endif return 0; } @@ -73,6 +76,9 @@ void psCryptoClose(void) *g_config = 'N'; psClosePrng(); psCoreClose(); +#ifdef USE_CRL + psCrlClose(); +#endif } } diff --git a/crypto/math/pstm.c b/crypto/math/pstm.c index 8e8f7df..cf47e8e 100644 --- a/crypto/math/pstm.c +++ b/crypto/math/pstm.c @@ -1685,8 +1685,10 @@ int32_t pstm_mulmod(psPool_t *pool, const pstm_int *a, const pstm_int *b, /******************************************************************************/ /* - * y = g**x (mod b) - * Some restrictions... x must be positive and < b + * y = g**x (mod p) + * Some restrictions... + * x must be positive and < p + * p must be positive, odd, and [512,1024,1536,2048,3072,4096] bits */ int32_t pstm_exptmod(psPool_t *pool, const pstm_int *G, const pstm_int *X, const pstm_int *P, pstm_int *Y) @@ -1698,6 +1700,19 @@ int32_t pstm_exptmod(psPool_t *pool, const pstm_int *G, const pstm_int *X, int16 bitcpy, bitcnt, mode, digidx, x, y, winsize; uint32 paDlen; + x = pstm_count_bits(P); + switch(x) { + case 512: + case 1024: + case 1536: + case 2048: + case 3072: + case 4096: + break; + default: + psTraceIntCrypto("pstm_exptmod prime size failed: %hu\n", x); + return -1; + } /* set window size from what user set as optimization */ x = pstm_count_bits(X); if (x < 50) { @@ -1999,6 +2014,9 @@ static void pstm_reverse(unsigned char *s, uint16_t len) uint16_t ix, iy; unsigned char t; + if (len == 0) { + return; + } ix = 0; iy = len - 1; while (ix < iy) { diff --git a/crypto/math/pstm_montgomery_reduce.c b/crypto/math/pstm_montgomery_reduce.c index c02a980..7cd0c5a 100644 --- a/crypto/math/pstm_montgomery_reduce.c +++ b/crypto/math/pstm_montgomery_reduce.c @@ -62,7 +62,7 @@ asm( \ "movl %%edx,%1 \n\t" \ :"=g"(_c[LO]), "=r"(cy) \ :"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++) \ -: "%eax", "%edx", "%cc") +: "%eax", "%edx", "cc") #define PROPCARRY \ asm( \ @@ -71,7 +71,7 @@ asm( \ "movzbl %%al,%1 \n\t" \ :"=g"(_c[LO]), "=r"(cy) \ :"0"(_c[LO]), "1"(cy) \ -: "%eax", "%cc") +: "%eax", "cc") /******************************************************************************/ #elif defined(PSTM_X86_64) @@ -224,7 +224,7 @@ asm( \ " STR r0,%1 \n\t" \ :"=r"(cy),"=m"(_c[0])\ :"0"(cy),"r"(mu),"r"(*tmpm++),"m"(_c[0])\ - :"r0","%cc"); + :"r0","cc"); #define PROPCARRY \ asm( \ " LDR r0,%1 \n\t" \ @@ -235,7 +235,7 @@ asm( \ " MOVCC %0,#0 \n\t" \ :"=r"(cy),"=m"(_c[0])\ :"0"(cy),"m"(_c[0])\ - :"r0","%cc"); + :"r0","cc"); #else /* Non-Thumb2 code */ //#pragma message ("Using 32 bit ARM Assembly Optimizations") #define INNERMUL \ @@ -248,7 +248,7 @@ asm( \ " STR r0,%1 \n\t" \ :"=r"(cy),"=m"(_c[0])\ :"0"(cy),"r"(mu),"r"(*tmpm++),"m"(_c[0])\ - :"r0","%cc"); + :"r0","cc"); #define PROPCARRY \ asm( \ " LDR r0,%1 \n\t" \ @@ -258,7 +258,7 @@ asm( \ " MOVCC %0,#0 \n\t" \ :"=r"(cy),"=m"(_c[0])\ :"0"(cy),"m"(_c[0])\ - :"r0","%cc"); + :"r0","cc"); #endif /* __thumb2__ */ /******************************************************************************/ diff --git a/crypto/math/pstm_mul_comba.c b/crypto/math/pstm_mul_comba.c index e7058ad..f81845c 100644 --- a/crypto/math/pstm_mul_comba.c +++ b/crypto/math/pstm_mul_comba.c @@ -74,7 +74,7 @@ asm( \ "addl %%eax,%0 \n\t" \ "adcl %%edx,%1 \n\t" \ "adcl $0,%2 \n\t" \ - :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%edx","%cc"); + :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%edx","cc"); /******************************************************************************/ #elif defined(PSTM_X86_64) @@ -143,7 +143,7 @@ asm( \ " ADDS %0,%0,r0 \n\t" \ " ADCS %1,%1,r1 \n\t" \ " ADC %2,%2,#0 \n\t" \ - :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "%cc"); + :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc"); /******************************************************************************/ #elif defined(PSTM_MIPS) diff --git a/crypto/math/pstm_sqr_comba.c b/crypto/math/pstm_sqr_comba.c index 2dd3dcb..e337767 100644 --- a/crypto/math/pstm_sqr_comba.c +++ b/crypto/math/pstm_sqr_comba.c @@ -67,7 +67,7 @@ asm( \ "addl %%eax,%0 \n\t" \ "adcl %%edx,%1 \n\t" \ "adcl $0,%2 \n\t" \ - :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%edx","%cc"); + :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%edx","cc"); #define SQRADD2(i, j) \ asm( \ @@ -79,7 +79,7 @@ asm( \ "addl %%eax,%0 \n\t" \ "adcl %%edx,%1 \n\t" \ "adcl $0,%2 \n\t" \ - :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%edx","%cc"); + :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%edx","cc"); #define SQRADDSC(i, j) \ asm( \ @@ -88,7 +88,7 @@ asm( \ "movl %%eax,%0 \n\t" \ "movl %%edx,%1 \n\t" \ "xorl %2,%2 \n\t" \ - :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","%cc"); + :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","cc"); #define SQRADDAC(i, j) \ asm( \ @@ -97,7 +97,7 @@ asm( \ "addl %%eax,%0 \n\t" \ "adcl %%edx,%1 \n\t" \ "adcl $0,%2 \n\t" \ - :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","%cc"); + :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","cc"); #define SQRADDDB \ asm( \ @@ -107,7 +107,7 @@ asm( \ "addl %6,%0 \n\t" \ "adcl %7,%1 \n\t" \ "adcl %8,%2 \n\t" \ - :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "%cc"); + :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc"); /******************************************************************************/ #elif defined(PSTM_X86_64) @@ -210,7 +210,7 @@ asm( \ " ADDS %0,%0,r0 \n\t" \ " ADCS %1,%1,r1 \n\t" \ " ADC %2,%2,#0 \n\t" \ -:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i) : "r0", "r1", "%cc"); +:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i) : "r0", "r1", "cc"); /* for squaring some of the terms are doubled... */ #define SQRADD2(i, j) \ @@ -222,13 +222,13 @@ asm( \ " ADDS %0,%0,r0 \n\t" \ " ADCS %1,%1,r1 \n\t" \ " ADC %2,%2,#0 \n\t" \ -:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "%cc"); +:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc"); #define SQRADDSC(i, j) \ asm( \ " UMULL %0,%1,%6,%7 \n\t" \ " SUB %2,%2,%2 \n\t" \ -:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "%cc"); +:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "cc"); #define SQRADDAC(i, j) \ asm( \ @@ -236,7 +236,7 @@ asm( \ " ADDS %0,%0,r0 \n\t" \ " ADCS %1,%1,r1 \n\t" \ " ADC %2,%2,#0 \n\t" \ -:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "r0", "r1", "%cc"); +:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "r0", "r1", "cc"); #define SQRADDDB \ asm( \ @@ -246,7 +246,7 @@ asm( \ " ADDS %0,%0,%3 \n\t" \ " ADCS %1,%1,%4 \n\t" \ " ADC %2,%2,%5 \n\t" \ -:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "%cc"); +:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc"); /******************************************************************************/ #elif defined(PSTM_MIPS) @@ -317,7 +317,7 @@ asm( \ " mflo %0 \n\t" \ " mfhi %1 \n\t" \ " xor %2,%2,%2 \n\t" \ - :"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "%cc"); + :"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc"); #define SQRADDAC(i, j) \ asm( \ diff --git a/crypto/prng/prng.c b/crypto/prng/prng.c index 863d759..9084b41 100644 --- a/crypto/prng/prng.c +++ b/crypto/prng/prng.c @@ -48,7 +48,7 @@ static short gPrngInit = 0; void psOpenPrng(void) { #ifdef USE_MULTITHREADING - psCreateMutex(&prngLock); + psCreateMutex(&prngLock, 0); #endif /* NOTE: if a PRNG is enabled, the low level psGetEntropy call can't have a useful userPtr context becuase there will be no session diff --git a/crypto/pubkey/dh.c b/crypto/pubkey/dh.c index a5ec6f8..9308918 100644 --- a/crypto/pubkey/dh.c +++ b/crypto/pubkey/dh.c @@ -259,6 +259,21 @@ int32_t psDhGenKey(psPool_t *pool, uint16_t keysize, int32_t rc; pstm_int p, g; + if (keysize > pLen) { + psTraceCrypto("psDhGenKey: keysize > pLen\n"); + return PS_FAIL; + } + switch(pLen) { + case 128: + case 192: + case 256: + case 384: + case 512: + break; + default: + psTraceCrypto("psDhGenKey: invalid keysize\n"); + return PS_FAIL; + } /* Convert the p and g into ints and make keys */ if ((rc = pstm_init_for_read_unsigned_bin(pool, &p, pLen)) != PS_SUCCESS) { return rc; @@ -300,6 +315,10 @@ int32_t psDhGenKeyInts(psPool_t *pool, uint16_t keysize, if (key == NULL) { return PS_ARG_FAIL; } + /* Detect parameters with too small g. */ + if (pstm_count_bits(g) < 2) { + return PS_ARG_FAIL; + } privsize = keysize; #ifndef USE_LARGE_DH_PRIVATE_KEYS /* @@ -414,6 +433,18 @@ int32_t psDhGenSharedSecret(psPool_t *pool, if ((err = pstm_read_unsigned_bin(&p, pBin, pBinLen)) != PS_SUCCESS) { goto error; } + /* Check key->pub is within correct range 2 <= pub < p - 1. */ + if (pstm_count_bits(&pubKey->pub) < 2) { + err = PS_FAILURE; + goto error; + } + if ((err = pstm_add_d(pool, &pubKey->pub, 1, &tmp)) != PSTM_OKAY) { + goto error; + } + if (pstm_cmp(&p, &tmp) != PSTM_GT) { + err = PS_FAILURE; + goto error; + } if ((err = pstm_exptmod(pool, &pubKey->pub, &privKey->priv, &p, &tmp)) != PS_SUCCESS) { goto error; diff --git a/crypto/pubkey/pubkey.h b/crypto/pubkey/pubkey.h index 5a57b91..7ef23c4 100644 --- a/crypto/pubkey/pubkey.h +++ b/crypto/pubkey/pubkey.h @@ -157,7 +157,7 @@ enum PACKED { /** Public Key types for psPubKey_t */ enum PACKED { - PS_NONE = 0, + PS_NOKEY = 0, PS_RSA, PS_ECC, PS_DH diff --git a/crypto/pubkey/rsa.c b/crypto/pubkey/rsa.c index 2a354ff..a6cba99 100644 --- a/crypto/pubkey/rsa.c +++ b/crypto/pubkey/rsa.c @@ -655,6 +655,11 @@ int32_t psRsaEncryptPriv(psPool_t *pool, psRsaKey_t *key, int32_t err; uint16_t size, olen; + /** @security We follow the FIPS 186 recommendation for minimum data to sign. */ + if (inlen < 28) { + psTraceCrypto("Error inlen < 28 bytes in psRsaEncryptPriv\n"); + return PS_ARG_FAIL; + } size = key->size; if (outlen < size) { psTraceCrypto("Error on bad outlen parameter to psRsaEncryptPriv\n"); diff --git a/crypto/symmetric/aesGCM.c b/crypto/symmetric/aesGCM.c index ea79e34..2653caa 100644 --- a/crypto/symmetric/aesGCM.c +++ b/crypto/symmetric/aesGCM.c @@ -114,6 +114,21 @@ void psAesReadyGCM(psAesGcm_t *ctx, psGhashPad(ctx); } +int32_t psAesReadyGCMRandomIV(psAesGcm_t *ctx, + unsigned char IV[12], + const unsigned char *aad, uint16_t aadLen, + void *poolUserPtr) +{ + int32_t res; + + res = psGetPrng(NULL, IV, 12, poolUserPtr); + if (res == 12) { + res = PS_SUCCESS; + psAesReadyGCM(ctx, IV, aad, aadLen); + } + return res; +} + /******************************************************************************/ /* Internal gcm crypt function that uses direction to determine what gets @@ -238,6 +253,23 @@ int32_t psAesDecryptGCM(psAesGcm_t *ctx, return PS_SUCCESS; } +int32_t psAesDecryptGCM2(psAesGcm_t *ctx, + const unsigned char *ct, + unsigned char *pt, uint32_t len, + const unsigned char *tag, uint32_t tagLen) +{ + unsigned char tagTmp[AES_BLOCKLEN]; + + psAesEncryptGCMx(ctx, ct, pt, len, 0); + psAesGetGCMTag(ctx, AES_BLOCKLEN, tagTmp); + + if (memcmpct(tag, tagTmp, tagLen) != 0) { + psTraceCrypto("GCM didn't authenticate\n"); + return PS_AUTH_FAIL; + } + return PS_SUCCESS; +} + /******************************************************************************/ /* Ghash code taken from FL diff --git a/crypto/symmetric/aes_aesni.c b/crypto/symmetric/aes_aesni.c index ee78a63..7e02d78 100644 --- a/crypto/symmetric/aes_aesni.c +++ b/crypto/symmetric/aes_aesni.c @@ -587,6 +587,21 @@ void psAesReadyGCM(psAesGcm_t *ctx, ctx->a_len = aadLen; } +int32_t psAesReadyGCMRandomIV(psAesGcm_t *ctx, + unsigned char IV[12], + const unsigned char *aad, uint16_t aadLen, + void *poolUserPtr) +{ + int32_t res; + + res = psGetPrng(NULL, IV, 12, poolUserPtr); + if (res == 12) { + res = PS_SUCCESS; + psAesReadyGCM(ctx, IV, aad, aadLen); + } + return res; +} + /* Encrypt pt to ct and update the internal hash state */ void psAesEncryptGCM(psAesGcm_t *ctx, const unsigned char *pt, unsigned char *ct, @@ -625,6 +640,22 @@ int32_t psAesDecryptGCM(psAesGcm_t *ctx, return PS_SUCCESS; } +/* Decrypt ct to pt and verify hash in ct */ +int32_t psAesDecryptGCM2(psAesGcm_t *ctx, + const unsigned char *ct, + unsigned char *pt, uint32_t len, + const unsigned char *tag, uint32_t tagLen) +{ + unsigned char tagTmp[16]; + + gcm_transform(ctx, pt, ct, len, ctx->IV, PS_AES_DECRYPT); + gcm_final(ctx, tagTmp); + if (memcmpct(tag, tagTmp, tagLen) != 0) { + return PS_AUTH_FAIL; + } + return PS_SUCCESS; +} + /* Just does the GCM decrypt portion. Doesn't expect the tag to be at the end of the ct. User will invoke psAesGetGCMTag seperately */ void psAesDecryptGCMtagless(psAesGcm_t *ctx, diff --git a/crypto/test/Makefile b/crypto/test/Makefile index 54e34d9..985005e 100755 --- a/crypto/test/Makefile +++ b/crypto/test/Makefile @@ -22,12 +22,18 @@ include $(MATRIXSSL_ROOT)/common.mk # Linked files STATICS:=../libcrypt_s.a $(MATRIXSSL_ROOT)/core/libcore_s.a +DIRS:=rsaperf eccperf dhperf + +.PHONY: $(DIRS) clean + all: compile -compile: $(OBJS) $(EXE) - $(MAKE) --directory=rsaperf - $(MAKE) --directory=eccperf - $(MAKE) --directory=dhperf +compile: $(OBJS) $(EXE) $(DIRS) + +# Note this requires MAKECMDGOALS to be defined by make, +# otherwise clean target doesn't work +$(DIRS): + $(MAKE) $(MAKECMDGOALS) --directory=$@ # Additional Dependencies $(OBJS): $(MATRIXSSL_ROOT)/common.mk Makefile $(wildcard *.h) @@ -38,9 +44,6 @@ $(SPEED_EXE): $(SPEED_SRC:.c=.o) $(STATICS) $(VECTOR_EXE): $(VECTOR_SRC:.c=.o) $(STATICS) $(CC) -o $@ $^ $(LDFLAGS) -clean: +clean: $(DIRS) rm -f $(EXE) $(OBJS) - $(MAKE) clean --directory=rsaperf - $(MAKE) clean --directory=eccperf - $(MAKE) clean --directory=dhperf diff --git a/crypto/test/algorithmTest.c b/crypto/test/algorithmTest.c index 3d689b4..e854d97 100644 --- a/crypto/test/algorithmTest.c +++ b/crypto/test/algorithmTest.c @@ -286,10 +286,11 @@ int32 psAesTestGCM(void) psAesGcm_t dCtx; unsigned char plaintext[4128]; unsigned char ciphertext[4128]; -#ifndef USE_ONLY_DECRYPT_GCM_WITH_TAG + unsigned char ciphertext_rand[4128]; + unsigned char plaintext_rand[4128]; unsigned char tag[16]; -#endif unsigned char ciphertext_with_tag[4144]; + unsigned char iv[12]; static unsigned char taglen[3] = { 8, 12, 16 }; static char *tagmsg[] = { " AES-GCM-%d known vector decrypt (taglen=8) test... ", @@ -808,6 +809,60 @@ int32 psAesTestGCM(void) printf("PASSED\n"); } + if (i == 1) { + _psTraceInt(" AES-GCM-%d long known vector random encrypt test... ", tests[i].keylen * 8); + } else { + _psTraceInt(" AES-GCM-%d known vector random encrypt test... ", tests[i].keylen * 8); + } + memcpy(iv, tests[i].iv, 12); + psAesInitGCM(&eCtx, tests[i].key, tests[i].keylen); + res = psAesReadyGCMRandomIV(&eCtx, iv, tests[i].aad, tests[i].aadlen, + NULL); + if (res != PS_SUCCESS) { + memset(ciphertext_rand, 0, sizeof ciphertext_rand); + } else { + if (tests[i].ptlen > 1024) { + /* Try multipart */ + psAesEncryptGCM(&eCtx, tests[i].pt, ciphertext_rand, + 1024); + psAesEncryptGCM(&eCtx, tests[i].pt + 1024, + ciphertext_rand + 1024, + tests[i].ptlen - 1024); + } else { + psAesEncryptGCM(&eCtx, tests[i].pt, ciphertext_rand, + tests[i].ptlen); + } + psAesGetGCMTag(&eCtx, 16, tag); + } + + if ((tests[i].ptlen >= 16 && + memcmp(ciphertext_rand, tests[i].ct, tests[i].ptlen) == 0) || + (memcmp(tag, tests[i].tag, 16) == 0)) { + printf("FAILED: Random IV failed or not used.\n"); + res = PS_FAILURE; + } else { + psAesInitGCM(&dCtx, tests[i].key, tests[i].keylen); + psAesReadyGCM(&dCtx, iv, tests[i].aad, tests[i].aadlen); + if (psAesDecryptGCM2(&dCtx, ciphertext_rand, plaintext_rand, + tests[i].ptlen, + tag, 16) != PS_SUCCESS || + memcmp(plaintext_rand, tests[i].pt, tests[i].ptlen) != 0) { + printf("FAILED: psAesDecryptGCM2 failed\n"); + res = PS_FAILURE; + } else { +#ifdef USE_VERBOSE_RANDOM_GCM + printf("PASSED [iv=%02x%02x%02x%02x%02x%02x" + "%02x%02x%02x%02x%02x%02x]\n", + iv[0], iv[1], iv[2], iv[3], + iv[4], iv[5], iv[6], iv[7], + iv[8], iv[9], iv[10], iv[11]); +#else + printf("PASSED\n"); +#endif + } + } + psAesClearGCM(&eCtx); + #ifndef USE_ONLY_DECRYPT_GCM_WITH_TAG _psTraceInt(" AES-GCM-%d known vector decrypt (tagless) test... ", tests[i].keylen * 8); psAesInitGCM(&dCtx, tests[i].key, tests[i].keylen); @@ -845,6 +900,23 @@ int32 psAesTestGCM(void) memset(plaintext, 0x0, 32); #endif /* !defined USE_ONLY_DECRYPT_GCM_WITH_TAG */ +#ifndef USE_LIBSODIUM_AES_GCM + _psTraceInt(" AES-GCM-%d known vector decrypt2 test... ", tests[i].keylen * 8); + psAesInitGCM(&dCtx, tests[i].key, tests[i].keylen); + psAesReadyGCM(&dCtx, tests[i].iv, tests[i].aad, tests[i].aadlen); + if (psAesDecryptGCM2(&dCtx, tests[i].ct, plaintext, tests[i].ptlen, + tests[i].tag, 16) != PS_SUCCESS || + memcmp(plaintext, tests[i].pt, tests[i].ptlen) != 0) { + printf("FAILED: psAesDecryptGCM2 failed\n"); + res = PS_FAILURE; + } else { + printf("PASSED\n"); + } + + psAesClearGCM(&dCtx); + memset(plaintext, 0x0, 32); +#endif /* !defined USE_LIBSODIUM_AES_GCM */ + for(l = 0; l < (int32) sizeof(taglen); l++) { _psTraceInt(tagmsg[l], tests[i].keylen * 8); memset(plaintext, 0x11, sizeof(plaintext)); @@ -871,15 +943,33 @@ int32 psAesTestGCM(void) memset(plaintext, 0x11, sizeof(plaintext)); memset(ciphertext_with_tag, 0x22, sizeof(ciphertext_with_tag)); memcpy(ciphertext_with_tag, tests[i].ct, tests[i].ptlen); - memcpy(ciphertext_with_tag + tests[i].ptlen, tests[i].tag, taglen[l]); + memcpy(ciphertext_with_tag + tests[i].ptlen, tests[i].tag, + taglen[l]); ciphertext_with_tag[tests[i].ptlen + taglen[l] - 1]++; psAesInitGCM(&dCtx, tests[i].key, tests[i].keylen); psAesReadyGCM(&dCtx, tests[i].iv, tests[i].aad, tests[i].aadlen); - if (psAesDecryptGCM(&dCtx, ciphertext_with_tag, tests[i].ptlen + taglen[l], + if (psAesDecryptGCM(&dCtx, ciphertext_with_tag, + tests[i].ptlen + taglen[l], plaintext, tests[i].ptlen) != PS_SUCCESS) { - printf("PASSED\n"); + + psAesClearGCM(&dCtx); + psAesInitGCM(&dCtx, tests[i].key, tests[i].keylen); + psAesReadyGCM(&dCtx, tests[i].iv, tests[i].aad, + tests[i].aadlen); + if (psAesDecryptGCM2(&dCtx, tests[i].ct, + plaintext, tests[i].ptlen, + ciphertext_with_tag + tests[i].ptlen, + taglen[l]) != PS_SUCCESS) { + printf("PASSED\n"); + } else { + printf("FAILED: verify accepts invalid tag (%s)\n", + "psAesDecryptGCM2"); + res = PS_FAILURE; + } + } else { - printf("FAILED: verify accepts invalid tag\n"); + printf("FAILED: verify accepts invalid tag (%s)\n", + "psAesDecryptGCM"); res = PS_FAILURE; } } diff --git a/crypto/test/rsaperf/rsaperf.c b/crypto/test/rsaperf/rsaperf.c index 9e160d3..1ade58f 100644 --- a/crypto/test/rsaperf/rsaperf.c +++ b/crypto/test/rsaperf/rsaperf.c @@ -2,7 +2,7 @@ * @file rsaperf.c * @version $Format:%h%d$ * - * RSA performance testing . + * RSA performance testing. */ /* * Copyright (c) 2013-2016 INSIDE Secure Corporation @@ -441,21 +441,22 @@ int main(int argc, char **argv) #endif /* SIGN_OP */ #ifdef VERIFY_OP - /* TODO: find a good way to time more than a single decrypt */ + static const unsigned char sigdata[] = "Test message to be signed - at least 28 bytes"; memset(in, 0x0, keysize); - memcpy(in, "hello", 5); - if (psRsaEncryptPriv(misc, &privkey, in, 5, out, keysize, pkaInfo) < 0) { + memcpy(in, sigdata, sizeof(sigdata)); + if (psRsaEncryptPriv(misc, &privkey, in, sizeof(sigdata), out, keysize, pkaInfo) < 0) { _psTrace(" FAILED VERIFY PREP\n"); } memset(in, 0x0, keysize); + /* TODO: find a good way to time more than a single decrypt */ psGetTime(&start, NULL); /* coverity[swapped_arguments] */ - if (psRsaDecryptPub(pool, &privkey, out, keysize, in, 5, pkaInfo) < 0) { + if (psRsaDecryptPub(pool, &privkey, out, keysize, in, sizeof(sigdata), pkaInfo) < 0) { _psTrace(" FAILED VERIFY OPERATION\n"); } psGetTime(&end, NULL); - if (memcmp(in, "hello", 5) != 0) { + if (memcmp(in, sigdata, sizeof(sigdata)) != 0) { _psTrace(" FAILED VERIFY VERIFY\n"); } _psTraceInt(TIME_UNITS "/verify ", t = psDiffMsecs(start, end, NULL)); diff --git a/matrixssl/cipherSuite.c b/matrixssl/cipherSuite.c index bffeee5..d80b002 100644 --- a/matrixssl/cipherSuite.c +++ b/matrixssl/cipherSuite.c @@ -791,18 +791,18 @@ const static sslCipherSpec_t supportedCiphers[] = { /* Ephemeral ciphersuites */ #ifdef USE_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - CS_ECDHE_ECDSA, - CRYPTO_FLAGS_AES256 | CRYPTO_FLAGS_GCM | CRYPTO_FLAGS_SHA3, + {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* ident */ + CS_ECDHE_ECDSA, /* type */ + CRYPTO_FLAGS_AES256 | CRYPTO_FLAGS_GCM | CRYPTO_FLAGS_SHA3, /* flags */ 0, /* macSize */ 32, /* keySize */ 4, /* ivSize */ 0, /* blocksize */ - csAesGcmInit, - csAesGcmEncrypt, - csAesGcmDecrypt, - NULL, - NULL}, + csAesGcmInit, /* init */ + csAesGcmEncrypt, /* encrypt */ + csAesGcmDecrypt, /* decrypt */ + NULL, /* generateMac */ + NULL}, /* verifyMac */ #endif /* USE_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 */ #ifdef USE_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 @@ -1678,10 +1678,10 @@ int32_t matrixSslSetCipherSuiteEnabledStatus(ssl_t *ssl, uint16_t cipherId, */ if (flags == PS_TRUE) { /* Unset the disabled bit */ - disabledCipherFlags[i >> 5] &= ~(1 < (i & 31)); + disabledCipherFlags[i >> 5] &= ~(1 << (i & 31)); } else { /* Set the disabled bit */ - disabledCipherFlags[i >> 5] |= 1 < (i & 31); + disabledCipherFlags[i >> 5] |= 1 << (i & 31); } return PS_SUCCESS; } else { @@ -2457,105 +2457,134 @@ const sslCipherSpec_t *sslGetCipherSpec(const ssl_t *ssl, uint16_t id) i = 0; do { - if (supportedCiphers[i].ident == id) { - /* Double check we support the requsted hash algorithm */ + if (supportedCiphers[i].ident != id) { + continue; + } + /* Double check we support the requsted hash algorithm */ #ifndef USE_MD5 - if (supportedCiphers[i].flags & CRYPTO_FLAGS_MD5) { - return NULL; - } + if (supportedCiphers[i].flags & CRYPTO_FLAGS_MD5) { + return NULL; + } #endif #ifndef USE_SHA1 - if (supportedCiphers[i].flags & CRYPTO_FLAGS_SHA1) { - return NULL; - } + if (supportedCiphers[i].flags & CRYPTO_FLAGS_SHA1) { + return NULL; + } #endif #if !defined(USE_SHA256) && !defined(USE_SHA384) - if (supportedCiphers[i].flags & CRYPTO_FLAGS_SHA2) { - return NULL; - } + if (supportedCiphers[i].flags & CRYPTO_FLAGS_SHA2) { + return NULL; + } #endif - /* Double check we support the requsted weak cipher algorithm */ + /* Double check we support the requsted weak cipher algorithm */ #ifndef USE_ARC4 - if (supportedCiphers[i].flags & - (CRYPTO_FLAGS_ARC4INITE | CRYPTO_FLAGS_ARC4INITD)) { - return NULL; - } + if (supportedCiphers[i].flags & + (CRYPTO_FLAGS_ARC4INITE | CRYPTO_FLAGS_ARC4INITD)) { + return NULL; + } #endif #ifndef USE_3DES - if (supportedCiphers[i].flags & CRYPTO_FLAGS_3DES) { - return NULL; - } + if (supportedCiphers[i].flags & CRYPTO_FLAGS_3DES) { + return NULL; + } #endif #ifdef USE_SERVER_SIDE_SSL - /* Globally disabled? */ - if (disabledCipherFlags[i >> 5] & (1 < (i & 31))) { - psTraceIntInfo("Matched cipher suite %d but disabled by user\n", - id); - return NULL; - } - /* Disabled for session? */ - if (id != 0) { /* Disable NULL_WITH_NULL_NULL not possible */ - for (j = 0; j < SSL_MAX_DISABLED_CIPHERS; j++) { - if (ssl->disabledCiphers[j] == id) { - psTraceIntInfo("Matched cipher suite %d but disabled by user\n", - id); - return NULL; - } - } - } -#endif /* USE_SERVER_SIDE_SSL */ -#ifdef USE_TLS_1_2 - /* Unusable because protocol doesn't allow? */ -#ifdef USE_DTLS - if (ssl->majVer == DTLS_MAJ_VER && - ssl->minVer != DTLS_1_2_MIN_VER) { - if (supportedCiphers[i].flags & CRYPTO_FLAGS_SHA3 || - supportedCiphers[i].flags & CRYPTO_FLAGS_SHA2) { - psTraceIntInfo("Matched cipher suite %d but only allowed in DTLS 1.2\n", - id); - return NULL; - } - } - if (!(ssl->flags & SSL_FLAGS_DTLS)) { -#endif - if (ssl->minVer != TLS_1_2_MIN_VER) { - if (supportedCiphers[i].flags & CRYPTO_FLAGS_SHA3 || - supportedCiphers[i].flags & CRYPTO_FLAGS_SHA2) { - psTraceIntInfo("Matched cipher suite %d but only allowed in TLS 1.2\n", - id); - return NULL; - } - } - - if (ssl->minVer == TLS_1_2_MIN_VER) { - if (supportedCiphers[i].flags & CRYPTO_FLAGS_MD5) { - psTraceIntInfo("Not allowing MD5 suite %d in TLS 1.2\n", + /* Globally disabled? */ + if (disabledCipherFlags[i >> 5] & (1 << (i & 31))) { + psTraceIntInfo("Matched cipher suite %d but disabled by user\n", + id); + return NULL; + } + /* Disabled for session? */ + if (id != 0) { /* Disable NULL_WITH_NULL_NULL not possible */ + for (j = 0; j < SSL_MAX_DISABLED_CIPHERS; j++) { + if (ssl->disabledCiphers[j] == id) { + psTraceIntInfo("Matched cipher suite %d but disabled by user\n", id); return NULL; } } + } +#endif /* USE_SERVER_SIDE_SSL */ +#ifdef USE_TLS_1_2 + /* Unusable because protocol doesn't allow? */ #ifdef USE_DTLS + if (ssl->majVer == DTLS_MAJ_VER && + ssl->minVer != DTLS_1_2_MIN_VER) { + if (supportedCiphers[i].flags & CRYPTO_FLAGS_SHA3 || + supportedCiphers[i].flags & CRYPTO_FLAGS_SHA2) { + psTraceIntInfo( + "Matched cipher suite %d but only allowed in DTLS 1.2\n", id); + return NULL; } + } + if (!(ssl->flags & SSL_FLAGS_DTLS)) { +#endif + if (ssl->minVer < TLS_1_2_MIN_VER) { + if (supportedCiphers[i].flags & CRYPTO_FLAGS_SHA3 || + supportedCiphers[i].flags & CRYPTO_FLAGS_SHA2) { + psTraceIntInfo( + "Matched cipher suite %d but only allowed in TLS 1.2\n", id); + return NULL; + } + } + if (ssl->minVer == TLS_1_2_MIN_VER) { + if (supportedCiphers[i].flags & CRYPTO_FLAGS_MD5) { + psTraceIntInfo("Not allowing MD5 suite %d in TLS 1.2\n", + id); + return NULL; + } + } +#ifdef USE_DTLS + } #endif #endif /* TLS_1_2 */ - /* The suite is available. Want to reject if current key material - does not support? */ + /** Check restrictions by HTTP2 (set by ALPN extension). + This should filter out all ciphersuites specified in: + https://tools.ietf.org/html/rfc7540#appendix-A + "Note: This list was assembled from the set of registered TLS + cipher suites at the time of writing. This list includes those + cipher suites that do not offer an ephemeral key exchange and + those that are based on the TLS null, stream, or block cipher type + (as defined in Section 6.2.3 of [TLS12]). Additional cipher + suites with these properties could be defined; these would not be + explicitly prohibited." + */ + if (ssl->flags & SSL_FLAGS_HTTP2) { + /** Only allow AEAD ciphers. */ + if (!(supportedCiphers[i].flags & CRYPTO_FLAGS_GCM) && + !(supportedCiphers[i].flags & CRYPTO_FLAGS_CHACHA)) { + + return NULL; + } + /** Only allow ephemeral key exchange. */ + switch (supportedCiphers[i].type) { + case CS_DHE_RSA: + case CS_ECDHE_ECDSA: + case CS_ECDHE_RSA: + break; + default: + return NULL; + } + } + + /* The suite is available. Want to reject if current key material + does not support? */ #ifdef VALIDATE_KEY_MATERIAL - if (ssl->keys != NULL) { - if (haveKeyMaterial(ssl, supportedCiphers[i].type, 0) - == PS_SUCCESS) { - return &supportedCiphers[i]; - } - psTraceIntInfo("Matched cipher suite %d but no supporting keys\n", - id); - } else { + if (ssl->keys != NULL) { + if (haveKeyMaterial(ssl, supportedCiphers[i].type, 0) + == PS_SUCCESS) { return &supportedCiphers[i]; } -#else + psTraceIntInfo("Matched cipher suite %d but no supporting keys\n", + id); + } else { return &supportedCiphers[i]; -#endif /* VALIDATE_KEY_MATERIAL */ } +#else + return &supportedCiphers[i]; +#endif /* VALIDATE_KEY_MATERIAL */ } while (supportedCiphers[i++].ident != SSL_NULL_WITH_NULL_NULL) ; return NULL; diff --git a/matrixssl/extDecode.c b/matrixssl/extDecode.c index 3956f49..d0e7327 100644 --- a/matrixssl/extDecode.c +++ b/matrixssl/extDecode.c @@ -688,6 +688,14 @@ static int dealWithAlpnExt(ssl_t *ssl, const unsigned char *c, unsigned short ex i--; } + /** HTTP2 places some constraints on TLS configuration, so flag + that here for checking later (in choosing cipher suite, etc). + @see https://tools.ietf.org/html/rfc7540#section-9.2 + */ + if ((ssl->alpnLen == 2) && memcmp(ssl->alpn, "h2", 2) = 0) { + ssl->flags |= SSL_FLAGS_HTTP2; + } + return PS_SUCCESS; } #endif /* USE_ALPN */ diff --git a/matrixssl/hsDecode.c b/matrixssl/hsDecode.c index 485f479..771fd6a 100644 --- a/matrixssl/hsDecode.c +++ b/matrixssl/hsDecode.c @@ -305,17 +305,24 @@ int32 parseClientHello(ssl_t *ssl, unsigned char **cp, unsigned char *end) suiteLen); return MATRIXSSL_ERROR; } - /* Now is 'suiteLen' bytes of the supported cipher suite list, - listed in order of preference. Loop through and find the - first cipher suite we support. */ + /* Now is 'suiteLen' bytes of the supported cipher suite list, + listed in order of preference. */ if (end - c < suiteLen) { ssl->err = SSL_ALERT_DECODE_ERROR; psTraceInfo("Malformed clientHello message\n"); return MATRIXSSL_ERROR; } - - /* Do want to make one entire pass of the cipher suites now - to search for SCSV if secure rehandshakes are on */ + /* We do not choose a ciphersuite yet, as the cipher we choose + may depend on an extension sent by the client. For example, + ALPN for HTTP/2 limits which suites we can negotiate, and + ELLIPTIC_CURVE/ELLIPTIC_POINT extensions may not match with + what we have available and we would have to fall back to a + non-ECC cipher. + Still, make one entire pass of the cipher suites now + to search for SCSV if secure rehandshakes are on. This is + the exception because SCSV is not a true ciphersuite, but + more like an extension that can be "hidden" for pre-TLS1.0 + implementations. */ suiteEnd = c + suiteLen; while (c < suiteEnd) { cipher = *c << 8; c++; @@ -340,7 +347,6 @@ int32 parseClientHello(ssl_t *ssl, unsigned char **cp, unsigned char *end) } } } - /* Compression parameters */ if (end - c < 1) { ssl->err = SSL_ALERT_DECODE_ERROR; @@ -1673,7 +1679,7 @@ PROTOCOL_DETERMINED: /******************************************************************************/ int32 parseServerKeyExchange(ssl_t *ssl, - unsigned char hsMsgHash[SHA384_HASH_SIZE], + unsigned char hsMsgHash[SHA512_HASH_SIZE], unsigned char **cp, unsigned char *end) { unsigned char *c; @@ -1689,7 +1695,7 @@ int32 parseServerKeyExchange(ssl_t *ssl, uint32 skeHashSigAlg; #endif #ifdef USE_RSA_CIPHER_SUITE - unsigned char sigOut[SHA384_HASH_SIZE]; + unsigned char sigOut[MAX_HASH_SIZE]; #endif #ifdef USE_ECC_CIPHER_SUITE uint32 res; diff --git a/matrixssl/matrixssl.c b/matrixssl/matrixssl.c index 12c9d9d..3ce6a10 100644 --- a/matrixssl/matrixssl.c +++ b/matrixssl/matrixssl.c @@ -54,14 +54,21 @@ static int32 verifyReadKeys(psPool_t *pool, sslKeys_t *keys, void *poolUserPtr); Static session table for session cache and lock for multithreaded env */ #ifdef USE_MULTITHREADING -static psMutex_t sessionTableLock; +static psMutex_t g_sessionTableLock; #ifdef USE_STATELESS_SESSION_TICKETS static psMutex_t g_sessTicketLock; #endif -#endif /* USE_MULTITHREADING */ +#endif -static sslSessionEntry_t sessionTable[SSL_SESSION_TABLE_SIZE]; -static DLListEntry sessionChronList; +#ifdef USE_SHARED_SESSION_CACHE +#include +#include +static sslSessionEntry_t *g_sessionTable; +#else +static sslSessionEntry_t g_sessionTable[SSL_SESSION_TABLE_SIZE]; +#endif + +static DLListEntry g_sessionChronList; static void initSessionEntryChronList(void); #endif /* USE_SERVER_SIDE_SSL */ @@ -89,14 +96,13 @@ static int32 matrixSslLoadKeyMaterialMem(sslKeys_t *keys, */ static char g_config[32] = "N"; -int32 matrixSslOpenWithConfig(const char *config) +int32_t matrixSslOpenWithConfig(const char *config) { - unsigned long clen; + unsigned long clen; + uint32_t shared; + int32_t rc; - /* Use copyright to avoid compiler warning about it being unused */ - if (*copyright != 'C') { - return PS_FAILURE; - } + (void)copyright; /* Prevent compiler warning. */ if (*g_config == 'Y') { return PS_SUCCESS; /* Function has been called previously */ } @@ -107,32 +113,48 @@ int32 matrixSslOpenWithConfig(const char *config) psErrorStr( "MatrixSSL config mismatch.\n" \ "Library: " MATRIXSSL_CONFIG \ "\nCurrent: %s\n", config); - return -1; + return PS_FAIL; } if (psCryptoOpen(config + clen) < 0) { psError("pscrypto open failure\n"); - return PS_FAILURE; + return PS_FAIL; } - #ifdef USE_SERVER_SIDE_SSL - memset(sessionTable, 0x0, +#ifdef USE_SHARED_SESSION_CACHE + g_sessionTable = (sslSessionEntry_t *)mmap(NULL, + sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (g_sessionTable == MAP_FAILED) { + psError("error creating shared memory\n"); + return PS_PLATFORM_FAIL; + } + psTraceStrInfo("Shared sessionTable = %p\n", g_sessionTable); + shared = PS_SHARED; +#else + shared = 0; +#endif + memset(g_sessionTable, 0x0, sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE); - initSessionEntryChronList(); -#ifdef USE_MULTITHREADING - psCreateMutex(&sessionTableLock); + + if ((rc = psCreateMutex(&g_sessionTableLock, shared)) < 0) { + return rc; + } #ifdef USE_STATELESS_SESSION_TICKETS - psCreateMutex(&g_sessTicketLock); + if ((rc = psCreateMutex(&g_sessTicketLock, shared)) < 0) { + return rc; + } #endif /* USE_STATELESS_SESSION_TICKETS */ -#endif /* USE_MULTITHREADING */ #endif /* USE_SERVER_SIDE_SSL */ #ifdef USE_DTLS - matrixDtlsSetPmtu(-1); #ifdef USE_SERVER_SIDE_SSL - dtlsGenCookieSecret(); + if ((rc = dtlsGenCookieSecret()) < 0) { + return rc; + } #endif + matrixDtlsSetPmtu(-1); #endif /* USE_DTLS */ return PS_SUCCESS; @@ -144,24 +166,29 @@ int32 matrixSslOpenWithConfig(const char *config) void matrixSslClose(void) { #ifdef USE_SERVER_SIDE_SSL - int32 i; + int i; -#ifdef USE_MULTITHREADING - psLockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + if (psLockMutex(&g_sessionTableLock) < 0) { + psTraceInfo("Warning: closing lock mutex failed\n"); + } for (i = 0; i < SSL_SESSION_TABLE_SIZE; i++) { - if (sessionTable[i].inUse > 1) { + if (g_sessionTable[i].inUse > 1) { psTraceInfo("Warning: closing while session still in use\n"); } } - memset(sessionTable, 0x0, + memset(g_sessionTable, 0x0, sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE); -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); - psDestroyMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + if (psUnlockMutex(&g_sessionTableLock) < 0) { + psTraceInfo("Warning: closing unlock mutex failed\n"); + } + psDestroyMutex(&g_sessionTableLock); +#ifdef USE_SHARED_SESSION_CACHE + if (munmap(g_sessionTable, + sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE) != 0) { + psTraceInfo("Warning: munmap call failed.\n"); + } +#endif #endif /* USE_SERVER_SIDE_SSL */ - psCryptoClose(); *g_config = 'N'; } @@ -190,7 +217,7 @@ int32_t matrixSslNewKeys(sslKeys_t **keys, void *memAllocUserPtr) lkeys->poolUserPtr = memAllocUserPtr; #if defined(USE_ECC) || defined(REQUIRE_DH_PARAMS) - rc = psCreateMutex(&lkeys->cache.lock); + rc = psCreateMutex(&lkeys->cache.lock, 0); if (rc < 0) { psFree(lkeys, pool); return rc; @@ -1837,14 +1864,14 @@ void matrixSslSetCertValidator(ssl_t *ssl, sslCertCb_t certValidator) static void initSessionEntryChronList(void) { uint32 i; - DLListInit(&sessionChronList); + DLListInit(&g_sessionChronList); /* Assign every session table entry with their ID from the start */ for (i = 0; i < SSL_SESSION_TABLE_SIZE; i++) { - DLListInsertTail(&sessionChronList, &sessionTable[i].chronList); - sessionTable[i].id[0] = (unsigned char)(i & 0xFF); - sessionTable[i].id[1] = (unsigned char)((i & 0xFF00) >> 8); - sessionTable[i].id[2] = (unsigned char)((i & 0xFF0000) >> 16); - sessionTable[i].id[3] = (unsigned char)((i & 0xFF000000) >> 24); + DLListInsertTail(&g_sessionChronList, &g_sessionTable[i].chronList); + g_sessionTable[i].id[0] = (unsigned char)(i & 0xFF); + g_sessionTable[i].id[1] = (unsigned char)((i & 0xFF00) >> 8); + g_sessionTable[i].id[2] = (unsigned char)((i & 0xFF0000) >> 16); + g_sessionTable[i].id[3] = (unsigned char)((i & 0xFF000000) >> 24); } } @@ -1889,27 +1916,21 @@ int32 matrixRegisterSession(ssl_t *ssl) Iterate the session table, looking for an empty entry (cipher null), or the oldest entry that is not in use */ -#ifdef USE_MULTITHREADING - psLockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psLockMutex(&g_sessionTableLock); - if (DLListIsEmpty(&sessionChronList)) { + if (DLListIsEmpty(&g_sessionChronList)) { /* All in use */ -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psUnlockMutex(&g_sessionTableLock); return PS_LIMIT_FAIL; } /* GetHead Detaches */ - pList = DLListGetHead(&sessionChronList); + pList = DLListGetHead(&g_sessionChronList); sess = DLListGetContainer(pList, sslSessionEntry_t, chronList); id = sess->id; i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; if (i >= SSL_SESSION_TABLE_SIZE) { -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psUnlockMutex(&g_sessionTableLock); return PS_LIMIT_FAIL; } @@ -1917,10 +1938,10 @@ int32 matrixRegisterSession(ssl_t *ssl) Register the incoming masterSecret and cipher, which could still be null, depending on when we're called. */ - memcpy(sessionTable[i].masterSecret, ssl->sec.masterSecret, + memcpy(g_sessionTable[i].masterSecret, ssl->sec.masterSecret, SSL_HS_MASTER_SIZE); - sessionTable[i].cipher = ssl->cipher; - sessionTable[i].inUse += 1; + g_sessionTable[i].cipher = ssl->cipher; + g_sessionTable[i].inUse += 1; /* The sessionId is the current serverRandom value, with the first 4 bytes replaced with the current cache index value for quick lookup later. @@ -1931,26 +1952,24 @@ int32 matrixRegisterSession(ssl_t *ssl) random used to generate the master key, even if he had not seen it initially. */ - memcpy(sessionTable[i].id + 4, ssl->sec.serverRandom, + memcpy(g_sessionTable[i].id + 4, ssl->sec.serverRandom, min(SSL_HS_RANDOM_SIZE, SSL_MAX_SESSION_ID_SIZE) - 4); ssl->sessionIdLen = SSL_MAX_SESSION_ID_SIZE; - memcpy(ssl->sessionId, sessionTable[i].id, SSL_MAX_SESSION_ID_SIZE); + memcpy(ssl->sessionId, g_sessionTable[i].id, SSL_MAX_SESSION_ID_SIZE); /* startTime is used to check expiry of the entry The versions are stored, because a cached session must be reused with same SSL version. */ - psGetTime(&sessionTable[i].startTime, ssl->userPtr); - sessionTable[i].majVer = ssl->majVer; - sessionTable[i].minVer = ssl->minVer; + psGetTime(&g_sessionTable[i].startTime, ssl->userPtr); + g_sessionTable[i].majVer = ssl->majVer; + g_sessionTable[i].minVer = ssl->minVer; - sessionTable[i].extendedMasterSecret = ssl->extFlags.extended_master_secret; + g_sessionTable[i].extendedMasterSecret = ssl->extFlags.extended_master_secret; -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psUnlockMutex(&g_sessionTableLock); return i; } @@ -1972,12 +1991,10 @@ int32 matrixClearSession(ssl_t *ssl, int32 remove) if (i >= SSL_SESSION_TABLE_SIZE) { return PS_LIMIT_FAIL; } -#ifdef USE_MULTITHREADING - psLockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ - sessionTable[i].inUse -= 1; - if (sessionTable[i].inUse == 0) { - DLListInsertTail(&sessionChronList, &sessionTable[i].chronList); + psLockMutex(&g_sessionTableLock); + g_sessionTable[i].inUse -= 1; + if (g_sessionTable[i].inUse == 0) { + DLListInsertTail(&g_sessionChronList, &g_sessionTable[i].chronList); } /* @@ -1990,14 +2007,12 @@ int32 matrixClearSession(ssl_t *ssl, int32 remove) ssl->sessionIdLen = 0; ssl->flags &= ~SSL_FLAGS_RESUMED; /* Always preserve the id for chronList */ - memset(sessionTable[i].id + 4, 0x0, SSL_MAX_SESSION_ID_SIZE - 4); - memset(sessionTable[i].masterSecret, 0x0, SSL_HS_MASTER_SIZE); - sessionTable[i].extendedMasterSecret = 0; - sessionTable[i].cipher = NULL; + memset(g_sessionTable[i].id + 4, 0x0, SSL_MAX_SESSION_ID_SIZE - 4); + memset(g_sessionTable[i].masterSecret, 0x0, SSL_HS_MASTER_SIZE); + g_sessionTable[i].extendedMasterSecret = 0; + g_sessionTable[i].cipher = NULL; } -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psUnlockMutex(&g_sessionTableLock); return PS_SUCCESS; } @@ -2021,13 +2036,9 @@ int32 matrixResumeSession(ssl_t *ssl) id = ssl->sessionId; i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0]; -#ifdef USE_MULTITHREADING - psLockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ - if (i >= SSL_SESSION_TABLE_SIZE || sessionTable[i].cipher == NULL) { -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psLockMutex(&g_sessionTableLock); + if (i >= SSL_SESSION_TABLE_SIZE || g_sessionTable[i].cipher == NULL) { + psUnlockMutex(&g_sessionTableLock); return PS_LIMIT_FAIL; } /* @@ -2035,46 +2046,38 @@ int32 matrixResumeSession(ssl_t *ssl) Expiration is done on daily basis (86400 seconds) */ psGetTime(&accessTime, ssl->userPtr); - if ((memcmp(sessionTable[i].id, id, + if ((memcmp(g_sessionTable[i].id, id, (uint32)min(ssl->sessionIdLen, SSL_MAX_SESSION_ID_SIZE)) != 0) || - (psDiffMsecs(sessionTable[i].startTime, accessTime, ssl->userPtr) > - SSL_SESSION_ENTRY_LIFE) || (sessionTable[i].majVer != ssl->majVer) - || (sessionTable[i].minVer != ssl->minVer)) { -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + (psDiffMsecs(g_sessionTable[i].startTime, accessTime, ssl->userPtr) > + SSL_SESSION_ENTRY_LIFE) || (g_sessionTable[i].majVer != ssl->majVer) + || (g_sessionTable[i].minVer != ssl->minVer)) { + psUnlockMutex(&g_sessionTableLock); return PS_FAILURE; } /* Enforce the RFC 7627 rules for resumpion and extended master secret. Essentially, a resumption must use (or not use) the extended master secret extension in step with the orginal connection */ - if (sessionTable[i].extendedMasterSecret == 0 && + if (g_sessionTable[i].extendedMasterSecret == 0 && ssl->extFlags.extended_master_secret == 1) { -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psUnlockMutex(&g_sessionTableLock); return PS_FAILURE; } - if (sessionTable[i].extendedMasterSecret == 1 && + if (g_sessionTable[i].extendedMasterSecret == 1 && ssl->extFlags.extended_master_secret == 0) { -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psUnlockMutex(&g_sessionTableLock); return PS_FAILURE; } /* Looks good */ - memcpy(ssl->sec.masterSecret, sessionTable[i].masterSecret, + memcpy(ssl->sec.masterSecret, g_sessionTable[i].masterSecret, SSL_HS_MASTER_SIZE); - ssl->cipher = sessionTable[i].cipher; - sessionTable[i].inUse += 1; - if (sessionTable[i].inUse == 1) { - DLListRemove(&sessionTable[i].chronList); + ssl->cipher = g_sessionTable[i].cipher; + g_sessionTable[i].inUse += 1; + if (g_sessionTable[i].inUse == 1) { + DLListRemove(&g_sessionTable[i].chronList); } -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + psUnlockMutex(&g_sessionTableLock); return PS_SUCCESS; } @@ -2105,28 +2108,22 @@ int32 matrixUpdateSession(ssl_t *ssl) /* If there is an error on the session, invalidate for any future use */ -#ifdef USE_MULTITHREADING - psLockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ - sessionTable[i].inUse += ssl->flags & SSL_FLAGS_CLOSED ? -1 : 0; - if (sessionTable[i].inUse == 0) { + psLockMutex(&g_sessionTableLock); + g_sessionTable[i].inUse += ssl->flags & SSL_FLAGS_CLOSED ? -1 : 0; + if (g_sessionTable[i].inUse == 0) { /* End of the line */ - DLListInsertTail(&sessionChronList, &sessionTable[i].chronList); + DLListInsertTail(&g_sessionChronList, &g_sessionTable[i].chronList); } if (ssl->flags & SSL_FLAGS_ERROR) { - memset(sessionTable[i].masterSecret, 0x0, SSL_HS_MASTER_SIZE); - sessionTable[i].cipher = NULL; -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + memset(g_sessionTable[i].masterSecret, 0x0, SSL_HS_MASTER_SIZE); + g_sessionTable[i].cipher = NULL; + psUnlockMutex(&g_sessionTableLock); return PS_FAILURE; } - memcpy(sessionTable[i].masterSecret, ssl->sec.masterSecret, + memcpy(g_sessionTable[i].masterSecret, ssl->sec.masterSecret, SSL_HS_MASTER_SIZE); - sessionTable[i].cipher = ssl->cipher; -#ifdef USE_MULTITHREADING - psUnlockMutex(&sessionTableLock); -#endif /* USE_MULTITHREADING */ + g_sessionTable[i].cipher = ssl->cipher; + psUnlockMutex(&g_sessionTableLock); return PS_SUCCESS; } @@ -2145,9 +2142,7 @@ int32 matrixSslDeleteSessionTicketKey(sslKeys_t *keys, unsigned char name[16]) { psSessionTicketKeys_t *lkey, *prev; -#ifdef USE_MULTITHREADING psLockMutex(&g_sessTicketLock); -#endif lkey = keys->sessTickets; prev = NULL; while (lkey) { @@ -2158,33 +2153,25 @@ int32 matrixSslDeleteSessionTicketKey(sslKeys_t *keys, unsigned char name[16]) /* no more list == no more session ticket support */ psFree(lkey, keys->pool); keys->sessTickets = NULL; -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif return PS_SUCCESS; } /* first in list but not alone */ keys->sessTickets = lkey->next; psFree(lkey, keys->pool); -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif return PS_SUCCESS; } /* Middle of list. Join previous with our next */ prev->next = lkey->next; psFree(lkey, keys->pool); -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif return PS_SUCCESS; } prev = lkey; lkey = lkey->next; } -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif return PS_FAILURE; /* not found */ } @@ -2220,16 +2207,12 @@ int32 matrixSslLoadSessionTicketKeys(sslKeys_t *keys, return PS_LIMIT_FAIL; } -#ifdef USE_MULTITHREADING psLockMutex(&g_sessTicketLock); -#endif if (keys->sessTickets == NULL) { /* first one */ keys->sessTickets = psMalloc(keys->pool, sizeof(psSessionTicketKeys_t)); if (keys->sessTickets == NULL) { -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif return PS_MEM_FAIL; } keylist = keys->sessTickets; @@ -2243,16 +2226,12 @@ int32 matrixSslLoadSessionTicketKeys(sslKeys_t *keys, } if (i > SSL_SESSION_TICKET_LIST_LEN) { psTraceInfo("Session ticket list > SSL_SESSION_TICKET_LIST_LEN\n"); -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif return PS_LIMIT_FAIL; } keylist = psMalloc(keys->pool, sizeof(psSessionTicketKeys_t)); if (keylist == NULL) { -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif return PS_MEM_FAIL; } prev->next = keylist; @@ -2264,9 +2243,7 @@ int32 matrixSslLoadSessionTicketKeys(sslKeys_t *keys, memcpy(keylist->name, name, 16); memcpy(keylist->hashkey, hashkey, hashkeyLen); memcpy(keylist->symkey, symkey, symkeyLen); -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif return PS_SUCCESS; } @@ -2494,9 +2471,7 @@ int32 matrixUnlockSessionTicket(ssl_t *ssl, unsigned char *in, int32 inLen) } c = in; len = inLen; -#ifdef USE_MULTITHREADING psLockMutex(&g_sessTicketLock); -#endif if (getTicketKeys(ssl, c, &keys) < 0) { psTraceInfo("No key found for session ticket\n"); /* We've been unlocked in getTicketKeys */ @@ -2522,9 +2497,7 @@ int32 matrixUnlockSessionTicket(ssl_t *ssl, unsigned char *in, int32 inLen) psAesDecryptCBC(&ctx, c + 16, c + 16, len - 16 - 16 - L_HASHLEN); psAesClearCBC(&ctx); keys->inUse = 0; -#ifdef USE_MULTITHREADING psUnlockMutex(&g_sessTicketLock); -#endif /* decrypted marker */ enc = c + 16; diff --git a/matrixssl/matrixsslApi.c b/matrixssl/matrixsslApi.c index 991eaa5..127df96 100644 --- a/matrixssl/matrixsslApi.c +++ b/matrixssl/matrixsslApi.c @@ -516,7 +516,7 @@ int32 matrixSslGetWritebuf(ssl_t *ssl, unsigned char **buf, uint32 requestedLen) Now that requiredLen has been confirmed/created, return number of available plaintext bytes */ - if (requestedLen < (uint32)ssl->maxPtFrag) { + if (requestedLen <= (uint32)ssl->maxPtFrag) { requestedLen = sz - overhead; if (requestedLen > (uint32)ssl->maxPtFrag) { requestedLen = ssl->maxPtFrag; @@ -1510,81 +1510,5 @@ int32 matrixSslIsSessionCompressionOn(ssl_t *ssl) } #endif -#ifdef USE_CRL -/* - Called after key load if CRL location is expected to be embedded in the CA. - The user callback will be invoked with the URL and the responsibility of - the callback is to fetch the CRL and load it to the CA with matrixSslLoadCRL - - The numLoaded parameter indicates how many successful CRLs were loaded - if there are multiple CA files being processed here. - - Return codes: - < 0 - Error loading a CRL. numLoaded indicates if some success - 0 - No errors encountered. numLoaded could be 0 if no CRLs found -*/ -int32 matrixSslGetCRL(sslKeys_t *keys, int32 (*crlCb)(psPool_t *pool, - psX509Cert_t *CA, int append, char *url, uint32 urlLen), - int32 *numLoaded) -{ - psX509Cert_t *CA; - x509GeneralName_t *gn; - unsigned char *crlURI; - int32 rc, crlURILen; - - if (keys->CAcerts == NULL || crlCb == NULL) { - return PS_ARG_FAIL; - } - CA = keys->CAcerts; - - *numLoaded = rc = 0; - while (CA) { - if (CA->extensions.bc.cA > 0 && CA->extensions.crlDist != NULL) { - gn = CA->extensions.crlDist; - while (gn) { - if (gn->id == 6) { /* Only pass on URI types */ - crlURI = gn->data; - crlURILen = gn->dataLen; - /* Invoke user callback to go fetch and load the CRL. - Do not use the append flag. The specification says - that multiple names must be mechanims to access the - same CRL. */ - if (crlCb(keys->pool, CA, 0, (char*)crlURI, - crlURILen) < 0) { - rc = -1; - } - (*numLoaded)++; /* Callback successfully loaded this CRL */ - } else { - psTraceIntInfo("Unsupported CRL distro point format %d\n", - gn->id); - } - gn = gn->next; - } - } - CA = CA->next; - } - return rc; -} - -/* - If user already has a CRL buffer handy or call from the callback to load - a fetched one - - Return codes: - < 0 - Error loading CRL - >= 0 - Success -*/ -int32 matrixSslLoadCRL(psPool_t *pool, psX509Cert_t *CA, int append, - const char *CRLbin, int32 CRLbinLen, void *poolUserPtr) -{ - if (CA == NULL) { - return PS_ARG_FAIL; - } - - return psX509ParseCrl(pool, CA, append, (unsigned char*)CRLbin, CRLbinLen, - poolUserPtr); -} -#endif - /******************************************************************************/ diff --git a/matrixssl/matrixsslApi.h b/matrixssl/matrixsslApi.h index 21d12b9..ca856a9 100644 --- a/matrixssl/matrixsslApi.h +++ b/matrixssl/matrixsslApi.h @@ -41,8 +41,8 @@ extern "C" { #endif -#include "core/coreApi.h" -#include "crypto/cryptoApi.h" +#include "../core/coreApi.h" +#include "../crypto/cryptoApi.h" #include "matrixsslConfig.h" #include "matrixssllib.h" @@ -107,16 +107,6 @@ PSPUBLIC int32 matrixSslLoadPkcs12(sslKeys_t *keys, const unsigned char *importPass, int32 ipasslen, const unsigned char *macPass, int32 mpasslen, int32 flags); -#ifdef USE_CRL -PSPUBLIC int32 matrixSslGetCRL(sslKeys_t *keys, - int32 (*crlCb)(psPool_t *pool, psX509Cert_t *CA, - int append, char *url, uint32 urlLen), - int32 *numLoaded); -/* memAllcocUserPtr is for TMP_PKI */ -PSPUBLIC int32 matrixSslLoadCRL(psPool_t *pool, psX509Cert_t *CA, int append, - const char *CRLbin, int32 CRLbinLen, - void *poolUserPtr); -#endif #if defined(USE_OCSP) && defined(USE_SERVER_SIDE_SSL) PSPUBLIC int32_t matrixSslLoadOCSPResponse(sslKeys_t *keys, const unsigned char *OCSPResponseBuf, diff --git a/matrixssl/matrixsslCheck.h b/matrixssl/matrixsslCheck.h index e7ea37b..c2ba8a7 100644 --- a/matrixssl/matrixsslCheck.h +++ b/matrixssl/matrixsslCheck.h @@ -66,6 +66,15 @@ extern "C" { #endif #endif +#ifdef USE_SHARED_SESSION_CACHE +#ifndef POSIX +#error "USE_SHARED_SESSION_CACHE only implemented for POSIX platforms." +#endif +#ifndef USE_MULTITHREADING +#error "USE_MULTITHREADING required for USE_SHARED_MESSAGE_CACHE." +#endif +#endif + /******************************************************************************/ /* SHA1 and MD5 are essential elements for SSL key derivation during protocol diff --git a/matrixssl/matrixssllib.h b/matrixssl/matrixssllib.h index 0d991f5..fa7475c 100644 --- a/matrixssl/matrixssllib.h +++ b/matrixssl/matrixssllib.h @@ -184,6 +184,14 @@ extern "C" { */ //#define USE_CERT_CHAIN_PARSING /**< @note Setting does not affect security */ +/******************************************************************************/ +/** + Experimental support for process-shared server session cache. + This allows forked copies of a process to use the same session cache. + @pre Supported for POSIX environments only currently. +*/ +//#define USE_SHARED_SESSION_CACHE /**< @note Experimental */ + /******************************************************************************/ /** - USE_TLS versions must 'stack' for compiling purposes @@ -397,6 +405,7 @@ extern "C" { #define SSL_FLAGS_AEAD_R (1<<21) #define SSL_FLAGS_NONCE_W (1<<22) #define SSL_FLAGS_NONCE_R (1<<23) +#define SSL_FLAGS_HTTP2 (1<<24) #define SSL_FLAGS_INTERCEPTOR (1<<30) #define SSL_FLAGS_EAP_FAST (1<<31) @@ -644,11 +653,12 @@ static __inline uint16_t HASH_SIG_MASK(uint8_t hash, uint8_t sig) #define EXT_MAX_FRAGMENT_LEN 1 #define EXT_TRUSTED_CA_KEYS 3 #define EXT_TRUNCATED_HMAC 4 -#define EXT_STATUS_REQUEST 5 /* TODO: rm interceptor dup */ +#define EXT_STATUS_REQUEST 5 /* OCSP */ #define EXT_ELLIPTIC_CURVE 10 /* Client-send only */ #define EXT_ELLIPTIC_POINTS 11 #define EXT_SIGNATURE_ALGORITHMS 13 #define EXT_ALPN 16 +#define EXT_SIGNED_CERTIFICATE_TIMESTAMP 18 #define EXT_EXTENDED_MASTER_SECRET 23 #define EXT_SESSION_TICKET 35 #define EXT_RENEGOTIATION_INFO 0xFF01 @@ -1090,9 +1100,6 @@ struct ssl { sslSec_t sec; /* Security structure */ -//TODO -// tlsSessionKeys_t skeys; - sslKeys_t *keys; /* SSL public and private keys */ pkaAfter_t pkaAfter[2]; /* Cli-side cli-auth = two PKA in flight */ @@ -1411,7 +1418,7 @@ extern int32 parseServerHelloExtensions(ssl_t *ssl, int32 hsLen, extern int32 parseServerHelloDone(ssl_t *ssl, int32 hsLen, unsigned char **cp, unsigned char *end); extern int32 parseServerKeyExchange(ssl_t *ssl, - unsigned char hsMsgHash[SHA384_HASH_SIZE], + unsigned char hsMsgHash[SHA512_HASH_SIZE], unsigned char **cp, unsigned char *end); #ifdef USE_OCSP extern int32 parseCertificateStatus(ssl_t *ssl, int32 hsLen, unsigned char **cp, diff --git a/matrixssl/sslv3.c b/matrixssl/sslv3.c index b2b027f..ea62181 100644 --- a/matrixssl/sslv3.c +++ b/matrixssl/sslv3.c @@ -233,25 +233,29 @@ int32_t sslGenerateFinishedHash(psMd5Sha1_t *md, { psMd5_t omd5; psSha1_t osha1; + psMd5Sha1_t md5sha1; unsigned char ihash[SHA1_HASH_SIZE]; + + psMd5Sha1Cpy(&md5sha1, md); /* md5Hash = MD5(master_secret + pad2 + MD5(handshake_messages + sender + master_secret + pad1)); */ if (senderFlags >= 0) { - psMd5Update(&md->md5, + psMd5Update(&md5sha1.md5, (senderFlags & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4); } - psMd5Update(&md->md5, masterSecret, SSL_HS_MASTER_SIZE); - psMd5Update(&md->md5, pad1, sizeof(pad1)); - psMd5Final(&md->md5, ihash); + psMd5Update(&md5sha1.md5, masterSecret, SSL_HS_MASTER_SIZE); + psMd5Update(&md5sha1.md5, pad1, sizeof(pad1)); + psMd5Final(&md5sha1.md5, ihash); psMd5Init(&omd5); psMd5Update(&omd5, masterSecret, SSL_HS_MASTER_SIZE); psMd5Update(&omd5, pad2, sizeof(pad2)); psMd5Update(&omd5, ihash, MD5_HASH_SIZE); psMd5Final(&omd5, out); + /* The SHA1 hash is generated in the same way, except only 40 bytes of pad1 and pad2 are used due to a mistake in the original SSL3 spec. @@ -261,12 +265,12 @@ int32_t sslGenerateFinishedHash(psMd5Sha1_t *md, SHA1(handshake_messages + sender + master_secret + pad1)); */ if (senderFlags >= 0) { - psSha1Update(&md->sha1, + psSha1Update(&md5sha1.sha1, (senderFlags & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4); } - psSha1Update(&md->sha1, masterSecret, SSL_HS_MASTER_SIZE); - psSha1Update(&md->sha1, pad1, 40); - psSha1Final(&md->sha1, ihash); + psSha1Update(&md5sha1.sha1, masterSecret, SSL_HS_MASTER_SIZE); + psSha1Update(&md5sha1.sha1, pad1, 40); + psSha1Final(&md5sha1.sha1, ihash); psSha1Init(&osha1); psSha1Update(&osha1, masterSecret, SSL_HS_MASTER_SIZE); diff --git a/matrixssl/test/sslTest.c b/matrixssl/test/sslTest.c index 9a71a5d..b407205 100644 --- a/matrixssl/test/sslTest.c +++ b/matrixssl/test/sslTest.c @@ -46,7 +46,7 @@ milliseconds so most non-embedded platforms will report 0 msecs/conn for most stats. - Standard handshakes and client-auth handshakes (commercial only) are timed + Standard handshakes and client-auth handshakes are timed for each enabled cipher suite. The other handshake types will still run but will not be timed */ @@ -104,7 +104,9 @@ static void statCback(void *ssl, void *stat_ptr, int32 type, int32 value); Must define in matrixConfig.h: USE_SERVER_SIDE_SSL USE_CLIENT_SIDE_SSL - USE_CLIENT_AUTH (commercial only) + Optional: + USE_CLIENT_AUTH + USE_SECURE_REHANDSHAKES */ #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" diff --git a/matrixssl/version.h b/matrixssl/version.h index f0a822f..fdda73b 100644 --- a/matrixssl/version.h +++ b/matrixssl/version.h @@ -13,10 +13,10 @@ extern "C" { #endif -#define MATRIXSSL_VERSION "3.8.3-OPEN" +#define MATRIXSSL_VERSION "3.8.4-OPEN" #define MATRIXSSL_VERSION_MAJOR 3 #define MATRIXSSL_VERSION_MINOR 8 -#define MATRIXSSL_VERSION_PATCH 3 +#define MATRIXSSL_VERSION_PATCH 4 #define MATRIXSSL_VERSION_CODE "OPEN" #ifdef __cplusplus diff --git a/pgp.asc b/pgp.asc new file mode 100644 index 0000000..b5383c8 --- /dev/null +++ b/pgp.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2.0.14 (GNU/Linux) + +mQINBFeO0mMBEACxCB7D5JVdizXwb0TKKlXGFGBvJHCQvPZplHNXXxsfZUgdJg7v +THuNdu5eryy1EIvE5dFGnvoq/cOPXc9bKMj2zLEyeVTGm2nImzCTn3MMNGqrIv9g +vTlpPCSFX0HRlI426FqCqU+CKnNmn8H6IYsboACWRxiR9tF8CWR/6hMoHH4ltner +SWbrxrK1PlXzNTVXzCi9OLDcf8ZGI7JohxvYoRGIi10dR0nPj8YFh9wyRutG9+4K +vc19IrO5H0HaRW+qNTKeDFWb/KO/hfjXbencLNLi6ZuCvKxgLpLQZ+kJI8NAT1RF +Q/4Nnmw3bxn7eoOrJ/lDkueEOVTTurywG3dLj37kTfgZymskBxrjyzcKwXfLTFg4 +SVknuZRuN2PKMlQS+9SmqVj1RWHMBNKiv+WPCcGZKZgNRuVm7HOmzcIXC+jKe5qX +OyL7VAOGMdpDXUGVT6Q3wt/JBJC527dPe0iFjEjZQz9xCIEIrfUMCxJeukHKUD7f +2r0lXHY4DNgR12pl91bANrR/sEWZA+gn+FHCsL6jwWTUwToKm7wwkABu3gX182Dx +6Xi3wFVl5ccVpDQREDsLxibgw78Nja6ibPFs1U99P1OuEuDI18Y6xOionas+daC5 +6sSEcfRBJ/RxshQl/bA0vEcL1lPAQbnJhzKW74QVWXwqGTW3jmDcvpIo2QARAQAB +tClNYXRyaXhTU0wgU3VwcG9ydCA8c3VwcG9ydEBtYXRyaXhzc2wub3JnPokCPQQT +AQoAJwUCV47SYwIbAwUJA8JnAAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRCL +srOaJ5XGs4QfEACGBCjqVcbZOLWK/dZ0YgR+C/v8vLOm4etizudBeGRxpz8+DPAf +IEgng0YD3PQQPq7C4BsRdQlXGUr/mLKUMghQMN+IX77cdKVfR7Rj5m6B8LMsxA4q +ebcZIykHRXafqSZBneLRdJqfTXiMZHJDrEj+SijkDbYxL9UK/bZ1AuuPK2a19tef +ldFEewmcu5t6iCrJZYQKvnZaZYtTknpY5Q3+LhPQ+wu7NFfbctUMiIq/evT0ztUp +4A7BvddKvRHXwI6vUnOuiWsV9TQiYsAgYiy2SdAphVkvVedCwrhOKxuTlDOLzAUZ ++RVuMz0nK4zM9tg+/XAxJLOphV9HpIBcudWGO2RIL8YsBHezKNsJFiNNdhWbLgt9 +QA/XDXnDIP1mm2QCDCPfU6Wb8YC34NJ9maiFLuuc6hZiOvOxii8BcN+U2uWfMDld +B5d2sj2g9nADvDb4XJLzWi6AvHzekD6aQYWyFDkbFPMsuVAfKmv3DGRKXfYRdpmk +4yxIhlp7CyVGzeHYydJZQZSOr5fN6foLXxzfJx36b/n750itkZZ2KfZbf9nvMA+x ++dzXodzXpm21IYbdPM4iwnR5Tqv4uDTJd1xMDy/MLl3/4ytZ1cGchnZFjlp7QSFs +XA3d3laTxTCvuMdFasLS58fH0/E4vWEcp0A93koSoeRMe5niLTeMsSkeO7kCDQRX +jtJjARAAt7GFnYQdGth3bPgvAx5stRZKut5Iwj8VwHfSmM+8rYaJoCvigR9rbd1y +zDQvxrW1Q8Hl8pEwsRvYpYQZmhzRooSlWYV85Q3P2xk7QerguvoxT23Y70ZQjOkj +x8V2L6Il9LwE6vlVJN/pJoxTsrnaq2BKZnp6R6q5rw5OSo03ufEXk8lOl0yAAjkk +kedgw+UpYDSRwO+nIqSFzbmyJ6EyGXh+G+mB783zDRVlTP0Whj+gDLW1PBBJip89 +E3XwisEHwMbu0121v2ltYLhf3bB3o+CZUeIXhf1InA4mprN71TjmH/A24y/CWkYX +ZpmMvNKE6P8uJSVU5oDpIJtPRvo7DPObf8pBCj4AZ8NlzV6GazM0Wvcz/8pPSS2g +JTUHMwpuGn8yrtYnoKqqrInWSCkwgD84MUcCsjTUANP/Vq8v90n+ELD+hX9M3msQ +PK60f4z/3hyI/eHBiHU3LbvuJ4nhiAS4v0ujJ81IEimbgMaUsbBXDEqLMgISCaoY +hMzxFPr/yURafIkty4iGTGl1NI2qfY6EvM/V5U2y488kOtFjQI4gb9dM95QZbq45 +r3HiUuhQ3EW80BHK0UUfpzgotDaTT8ebqwRDecIvoEJaC8+xqVztSBVipNyNTrfT +qD+rmywqGL0LgRGfCQJLobvClE45q+o7sIfrKk3WAZazugIMb1kAEQEAAYkCJQQY +AQoADwUCV47SYwIbDAUJA8JnAAAKCRCLsrOaJ5XGs54iEACVYFoDGHrQVsXf2/Gb +u/hLtHIzv0OOHpua4wrvXn7hCEdAvy0IBUH63K2hATGPFn8j2IiLTQqqRaa/sSYe +Yjv/gZeNjnyxNNp1i24ej4LJaE0KmX+61rpAFfTMdv6hi4vu06lyw+nAcbXnJTYZ +CiJO2cqN5BlzTjQv4KYNQ5JjI98w42PCOssSAwPDbabnAF4+zCSKu0YWEGqsH5sK +z6g5rlKVxXPXFsHC5DJd63+JA/LbrptJYrBnTu5mFI2ETi8Ke05DYzpwWDG7AhI5 +pvJkVJpkWSS5CHnyVaG4//Azw0QmWwIjx01GGvHtY4wxPks5XtZ8KsM5/glEiOaY +VdbUsDviwXNCdzqZjfZ0Y1zN7uaqgGgaVnGubVKGJwUap+2j1tjfEGShLN6kkVvn +dK2uyGlos2WgPYlUUlCbv3hutv1RkosiQP38LegOgC7i3BEkQdVQHeBb3PGJI4YD +1KAUWKNYi3nvvZ2niyodxpblRFbz7rh66zDJZ61P0GBlH9ay3eAd7V8RWV07PKAH +tq40V6yOsQei9xyJrUmjfQipeE+XAG2fXYNEUJE/Ss5T0gGFkiA3ON8pCcMM64u4 +vZDOUAgVur9Qt6XjmgP8+V2TmCg6i5onmlobqu/vOaFZVhZSaWDF8ENRINGNWidm +jlkZfHBR7FeZ+zk4xUe4qQTxkw== +=ytP8 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/testkeys/RSA/4096_RSA_KEY.h b/testkeys/RSA/4096_RSA_KEY.h index 2f98169..5adda09 100644 --- a/testkeys/RSA/4096_RSA_KEY.h +++ b/testkeys/RSA/4096_RSA_KEY.h @@ -1,5 +1,5 @@ /** - * @file testkeys/RSA/4096_RSA_KEY.h + * @file 4096_RSA_KEY.h * @version $Format:%h%d$ * * Auto generated from PEM file. @@ -7,203 +7,152 @@ /* Auto generated private key as binary DER. */ -#define RSA4096KEY_SIZE 2348 +#define RSA4096KEY_SIZE 2349 const static unsigned char RSA4096KEY[RSA4096KEY_SIZE] = -{ - 0x30, 0x82, 0x09, 0x28, 0x02, 0x01, 0x00, 0x02, 0x82, 0x02, 0x01, 0x00, - 0xc8, 0xf2, 0xdb, 0x39, 0xad, 0xf4, 0x43, 0x97, 0xa2, 0x6d, 0x85, 0x2c, - 0x17, 0x14, 0x26, 0x25, 0xe9, 0x8f, 0xb8, 0x71, 0x3c, 0x58, 0x5b, 0x2d, - 0x18, 0x0f, 0xad, 0x76, 0xa7, 0xfe, 0x8f, 0x46, 0x4c, 0x67, 0xc3, 0x1e, - 0x70, 0xe0, 0x82, 0xd3, 0x77, 0x67, 0x9d, 0x6d, 0x76, 0xa2, 0xca, 0x79, - 0x70, 0xd2, 0xae, 0xbe, 0x21, 0xa6, 0xa7, 0x42, 0xea, 0x30, 0xcb, 0x96, - 0x15, 0xa6, 0x21, 0x62, 0x66, 0xa5, 0xdd, 0xff, 0x23, 0x78, 0xc9, 0xe0, - 0x9f, 0x73, 0xb8, 0x08, 0x1e, 0x0e, 0x49, 0x85, 0x8d, 0xdf, 0x55, 0x24, - 0x42, 0xc1, 0x4b, 0xc9, 0xde, 0x03, 0xa0, 0xcf, 0xc7, 0xaf, 0x25, 0xfd, - 0x6a, 0xe8, 0xea, 0xfc, 0xd3, 0x09, 0x85, 0xdb, 0x6b, 0x9e, 0x4a, 0x8d, - 0x71, 0x91, 0xe9, 0x84, 0xa7, 0x75, 0x6d, 0xdd, 0x2e, 0x60, 0x8c, 0xaf, - 0x30, 0xfa, 0xdd, 0x1e, 0x0d, 0x04, 0x5c, 0x7b, 0xc2, 0x35, 0x0d, 0xee, - 0x5b, 0xe5, 0x62, 0x81, 0xb9, 0x98, 0xf1, 0xce, 0x3f, 0x92, 0x59, 0x1f, - 0xd0, 0xe4, 0x17, 0x48, 0xfb, 0xfe, 0xa0, 0xb3, 0x2c, 0x7c, 0x01, 0xc0, - 0x19, 0x56, 0xa1, 0x20, 0x08, 0x06, 0x7d, 0x70, 0xf2, 0x2f, 0xb2, 0xad, - 0x44, 0xc2, 0xe4, 0x5b, 0x84, 0x2b, 0x98, 0x06, 0x87, 0xaf, 0x54, 0x2b, - 0xb7, 0xe4, 0xfe, 0x53, 0x2f, 0xf2, 0xd7, 0xb4, 0x34, 0x4d, 0x46, 0xdf, - 0x44, 0x2e, 0x72, 0x04, 0xd7, 0x34, 0x3e, 0xde, 0xbf, 0x55, 0x74, 0x7f, - 0x3e, 0xd4, 0xc3, 0x3d, 0x1f, 0x7c, 0x24, 0xf2, 0xed, 0x4f, 0x38, 0x1d, - 0xf4, 0xb2, 0x47, 0x5e, 0xe9, 0x2c, 0x23, 0xf3, 0xdd, 0xbb, 0x16, 0xd9, - 0x1c, 0xba, 0x53, 0x1a, 0x1c, 0xf1, 0x02, 0xf1, 0x8e, 0xec, 0x79, 0x5b, - 0xf9, 0x55, 0x21, 0x66, 0x12, 0x6f, 0x9e, 0xf0, 0x9e, 0x3f, 0xdc, 0xbe, - 0xd6, 0x31, 0x35, 0xc2, 0xf2, 0x78, 0xb6, 0x0a, 0x9b, 0x22, 0xa3, 0xa6, - 0x9d, 0xd3, 0xf5, 0x4f, 0x05, 0x49, 0x00, 0xc4, 0xc2, 0xc2, 0x87, 0x43, - 0x06, 0xfc, 0x43, 0x3c, 0xda, 0xf6, 0xfa, 0xbd, 0xf7, 0x99, 0xfb, 0xd5, - 0x64, 0x6f, 0x69, 0xd9, 0x4d, 0xb9, 0xc5, 0x1a, 0x07, 0xd6, 0xdf, 0x40, - 0xb7, 0x4a, 0x6b, 0x16, 0xc8, 0x2c, 0x23, 0x5f, 0xe2, 0xee, 0x7c, 0x66, - 0xdd, 0x3b, 0x7c, 0x80, 0x40, 0x9a, 0xb9, 0xd8, 0x99, 0xf7, 0xde, 0x71, - 0x3d, 0xf7, 0x35, 0x86, 0x0f, 0x6b, 0xf9, 0x01, 0xe9, 0x53, 0xf9, 0x17, - 0xcf, 0x1f, 0x6e, 0xf8, 0xac, 0xfa, 0x2f, 0x5f, 0x33, 0x13, 0x33, 0xfa, - 0xf1, 0xcf, 0x7d, 0x6b, 0xb9, 0xd6, 0xa3, 0x68, 0x16, 0x84, 0x60, 0x89, - 0x6f, 0x2c, 0xc8, 0xe7, 0xf2, 0xe0, 0xc9, 0x7f, 0x84, 0xce, 0xe9, 0x45, - 0x18, 0x96, 0x9a, 0x99, 0xac, 0x0e, 0x0e, 0x61, 0xea, 0x33, 0xbf, 0x3d, - 0xb1, 0x8b, 0x92, 0x9e, 0xdf, 0xc6, 0x75, 0x66, 0x56, 0x7a, 0x9a, 0xa9, - 0x9b, 0xd8, 0x77, 0x64, 0xad, 0xf6, 0x41, 0xc4, 0x32, 0x3b, 0x8e, 0xe9, - 0x90, 0x55, 0xfe, 0xe3, 0x0b, 0x2c, 0x43, 0x37, 0xaa, 0x8a, 0x79, 0x38, - 0xb4, 0x89, 0x9b, 0x2d, 0xac, 0xe7, 0x6e, 0x3f, 0x23, 0xb3, 0x30, 0xa2, - 0x84, 0x21, 0x97, 0x8d, 0x2d, 0x02, 0x14, 0xac, 0xfa, 0x67, 0x4b, 0x6c, - 0xbc, 0x33, 0xf5, 0x89, 0x88, 0x8a, 0x57, 0xdd, 0x96, 0x9c, 0x6a, 0x5a, - 0x06, 0x62, 0x33, 0xb1, 0xe0, 0xaa, 0x70, 0xc8, 0x05, 0x81, 0x82, 0x62, - 0x3d, 0xa0, 0x4c, 0xdf, 0x71, 0xa8, 0x7e, 0x7d, 0xb3, 0xc6, 0x70, 0xf1, - 0x60, 0xac, 0xd6, 0x46, 0xd8, 0x85, 0xb7, 0x6b, 0x5f, 0xb7, 0xa1, 0x86, - 0xb6, 0xf5, 0xca, 0xf6, 0xa2, 0x8d, 0xe9, 0x78, 0x37, 0x13, 0x1d, 0xe0, - 0xd3, 0x13, 0x9f, 0x0e, 0x20, 0x2c, 0x26, 0x87, 0x02, 0x03, 0x01, 0x00, - 0x01, 0x02, 0x82, 0x02, 0x00, 0x47, 0x8f, 0xcd, 0x28, 0x86, 0x5d, 0x85, - 0xb0, 0xbb, 0x84, 0x7b, 0x37, 0x8f, 0x64, 0x7a, 0x8d, 0x67, 0xd6, 0xe9, - 0xdd, 0x51, 0x9b, 0x39, 0xa5, 0x1e, 0x7b, 0x7e, 0xcf, 0xd1, 0xd5, 0xe2, - 0xda, 0x2b, 0x1d, 0x8c, 0xac, 0x0b, 0x90, 0xb8, 0xa6, 0x6c, 0x50, 0x77, - 0x0c, 0xe3, 0x81, 0xe7, 0xcf, 0x45, 0xb1, 0x91, 0xcf, 0x5e, 0x16, 0x86, - 0x5c, 0x5b, 0x20, 0x53, 0x70, 0x38, 0x77, 0x78, 0x4e, 0x1d, 0xb6, 0x16, - 0x0f, 0xe5, 0x66, 0xff, 0xa5, 0xc1, 0xc3, 0x29, 0x17, 0xa2, 0xf4, 0x7d, - 0x94, 0x55, 0x48, 0xe2, 0x7e, 0x4e, 0x53, 0x9e, 0x14, 0xde, 0xbe, 0xb6, - 0x07, 0x28, 0xda, 0xa4, 0x11, 0xd2, 0x7f, 0xee, 0x27, 0x69, 0x54, 0x6b, - 0xda, 0x0f, 0x42, 0x48, 0xd4, 0x84, 0x4c, 0x6d, 0x37, 0xf3, 0x96, 0xeb, - 0x30, 0x28, 0x72, 0xf3, 0xc6, 0xf4, 0x0f, 0x72, 0xad, 0x5f, 0xff, 0x5c, - 0x9c, 0x2a, 0x36, 0x50, 0xa6, 0xc1, 0x0d, 0x38, 0x7e, 0x70, 0x45, 0x1a, - 0x5f, 0xd3, 0xdd, 0xdf, 0x65, 0x68, 0x33, 0xc2, 0x63, 0x18, 0x72, 0xbe, - 0x71, 0xf0, 0x76, 0x9c, 0xfc, 0xf7, 0x49, 0x15, 0x8a, 0x5d, 0xb1, 0x49, - 0xfc, 0xee, 0x12, 0xb4, 0x73, 0xe6, 0x17, 0xed, 0xd0, 0xf5, 0x89, 0xbc, - 0xd3, 0x1e, 0x80, 0xfe, 0xdd, 0xae, 0xd8, 0x9b, 0x05, 0xae, 0xfe, 0xb1, - 0x78, 0x98, 0x63, 0xa8, 0xc8, 0x9b, 0xf4, 0x5a, 0x60, 0x84, 0xef, 0x33, - 0x30, 0x8a, 0x3c, 0xf9, 0x86, 0xd3, 0x2e, 0x5b, 0xf5, 0x29, 0x80, 0x41, - 0x7c, 0x4d, 0xac, 0xb7, 0x94, 0x5b, 0x6f, 0x1d, 0xe1, 0x9b, 0xf2, 0x3f, - 0x3f, 0x7a, 0x88, 0x45, 0x03, 0xbe, 0xaa, 0x50, 0x2b, 0xed, 0x80, 0x9b, - 0x06, 0xc1, 0x5a, 0x4f, 0x81, 0xc4, 0x92, 0x5f, 0x99, 0x85, 0x19, 0x41, - 0x25, 0xf9, 0x85, 0x4e, 0xac, 0x9b, 0x84, 0xdc, 0xda, 0xd4, 0xeb, 0xae, - 0xc5, 0xe5, 0xdc, 0x00, 0x09, 0x15, 0x75, 0x85, 0x4b, 0xf0, 0xe3, 0x31, - 0x87, 0x3d, 0xe5, 0x8e, 0xf1, 0x00, 0x20, 0xc7, 0x9b, 0xa4, 0xf2, 0x70, - 0x4e, 0x6e, 0x80, 0xe2, 0xbc, 0x35, 0x76, 0xae, 0xca, 0xc8, 0xb1, 0x47, - 0xe4, 0x26, 0x90, 0x57, 0xad, 0x15, 0xa4, 0x54, 0x71, 0x33, 0xb1, 0x71, - 0x98, 0x6d, 0x96, 0xc4, 0x8d, 0xc7, 0x34, 0xa9, 0x32, 0x6a, 0xef, 0xd8, - 0x0a, 0x86, 0x32, 0xe2, 0x89, 0x0a, 0xd1, 0xd8, 0x0a, 0x6a, 0x84, 0x14, - 0x77, 0xde, 0x3a, 0xb9, 0xd3, 0xda, 0xae, 0x17, 0xf8, 0x0c, 0x63, 0xa5, - 0x41, 0x56, 0x58, 0xa8, 0xc4, 0x84, 0xd1, 0xb2, 0xf8, 0xe3, 0x1d, 0xbf, - 0x91, 0xf7, 0xb4, 0x46, 0xd6, 0xc7, 0x53, 0xb2, 0xeb, 0x89, 0x28, 0x64, - 0x68, 0x80, 0xf4, 0x72, 0xf8, 0xd7, 0x50, 0xab, 0x27, 0x70, 0x5c, 0x4d, - 0x20, 0x43, 0x8c, 0x52, 0xa0, 0x55, 0xef, 0xff, 0xfb, 0x46, 0x8c, 0x62, - 0x14, 0x97, 0xd0, 0x55, 0x76, 0x2c, 0xe8, 0xe8, 0xa5, 0x96, 0x5d, 0x7c, - 0x0d, 0x01, 0xcf, 0xba, 0x32, 0x2e, 0x8c, 0x16, 0x40, 0x66, 0x46, 0x0d, - 0x50, 0x38, 0x2a, 0x65, 0x14, 0xe0, 0x34, 0xbe, 0x5d, 0xeb, 0xbe, 0xd6, - 0xfe, 0x8b, 0xa3, 0x6a, 0x11, 0x8b, 0xda, 0xbf, 0x7a, 0x55, 0x4a, 0x34, - 0xbf, 0x9b, 0x3d, 0x23, 0xd3, 0x6e, 0x9a, 0x3f, 0x4b, 0x60, 0x58, 0x84, - 0x31, 0x2b, 0xe8, 0x92, 0xed, 0x14, 0x57, 0x14, 0x08, 0xae, 0x21, 0x0f, - 0x0a, 0xd2, 0x9c, 0x75, 0x2f, 0x2d, 0xd0, 0x14, 0xb5, 0x14, 0xfa, 0xa1, - 0x1d, 0xef, 0xdf, 0x2a, 0xf8, 0x67, 0xc8, 0xb8, 0x9f, 0x1d, 0x89, 0xe9, - 0xe5, 0xa8, 0x44, 0x4f, 0x3a, 0xc4, 0xd5, 0xdb, 0xfa, 0xb2, 0x8b, 0x68, - 0x66, 0xbc, 0xdf, 0xb3, 0x68, 0x5b, 0x2c, 0x92, 0xf8, 0x49, 0xc3, 0x2d, - 0xf9, 0x02, 0x82, 0x01, 0x01, 0x00, 0xf7, 0x7c, 0x65, 0xc6, 0x43, 0x0b, - 0x60, 0x60, 0xfd, 0xfc, 0xe0, 0xcd, 0x37, 0xfc, 0x98, 0xfb, 0x6b, 0xb8, - 0x4f, 0x8b, 0xdb, 0x79, 0x0c, 0x52, 0xeb, 0x62, 0xd5, 0x44, 0x67, 0x4f, - 0x67, 0x11, 0x02, 0x5b, 0x37, 0x2f, 0xcc, 0x31, 0x17, 0x44, 0x42, 0x96, - 0x76, 0xc8, 0x5d, 0x46, 0x1b, 0xd7, 0xad, 0x7a, 0x4c, 0x16, 0xdc, 0xab, - 0x1d, 0xe9, 0x64, 0xd3, 0xc4, 0xe4, 0x46, 0x76, 0x05, 0xb4, 0x09, 0x8b, - 0xb3, 0xba, 0xca, 0x68, 0xba, 0xf0, 0x50, 0x7a, 0x24, 0x33, 0xc1, 0xb5, - 0xf2, 0xb7, 0xa0, 0xd8, 0xfd, 0xbd, 0x57, 0xe0, 0x32, 0x15, 0x9c, 0xb0, - 0xc3, 0x74, 0xd0, 0xb1, 0xe8, 0x26, 0xd8, 0xd1, 0x22, 0x56, 0x0e, 0xd7, - 0x39, 0xe6, 0xed, 0x0e, 0x62, 0x4c, 0x05, 0x37, 0x05, 0x7d, 0x19, 0x10, - 0xa7, 0xf2, 0x36, 0x76, 0x34, 0xee, 0xa7, 0xc0, 0x0a, 0xf8, 0x78, 0x2f, - 0x8d, 0xd4, 0x68, 0x44, 0xd1, 0x19, 0x39, 0x00, 0x8b, 0xa6, 0x9c, 0x48, - 0xcb, 0x4a, 0xe0, 0x53, 0x78, 0x8a, 0x0e, 0x52, 0xe4, 0xb2, 0xb2, 0x6a, - 0x19, 0xd8, 0xb2, 0x29, 0x54, 0xc3, 0xb7, 0x0f, 0xdd, 0x04, 0xa5, 0x73, - 0xec, 0x53, 0x8c, 0x80, 0xd7, 0x9e, 0x46, 0x14, 0xba, 0x0d, 0xa2, 0xaa, - 0xf2, 0xc6, 0x42, 0xa7, 0xbb, 0xbe, 0x16, 0x21, 0xb9, 0xe0, 0x4b, 0x28, - 0x3a, 0xec, 0x9a, 0x1f, 0x96, 0xff, 0x9b, 0x67, 0x34, 0x78, 0x81, 0xec, - 0x11, 0x8d, 0x86, 0x01, 0xdd, 0xb2, 0x32, 0xf7, 0x9b, 0xa1, 0x29, 0xfd, - 0xf7, 0xd7, 0x7a, 0x1f, 0x24, 0x86, 0x62, 0xcd, 0xa2, 0x73, 0x27, 0x87, - 0x1e, 0x3f, 0x45, 0xc1, 0xef, 0xf9, 0x2e, 0x1b, 0xa5, 0x0d, 0x69, 0x9f, - 0xc7, 0x70, 0xea, 0x55, 0xd7, 0x09, 0x7d, 0x0f, 0x65, 0xcd, 0xe5, 0xb6, - 0x6d, 0xd4, 0x77, 0x7d, 0xe1, 0xaf, 0xaf, 0xe6, 0x31, 0x45, 0x02, 0x82, - 0x01, 0x01, 0x00, 0xcf, 0xdc, 0x9b, 0x30, 0x30, 0x03, 0x1a, 0x74, 0xce, - 0x7b, 0xd2, 0x9a, 0x04, 0xda, 0x91, 0x27, 0xe8, 0x74, 0x7c, 0x1c, 0x4f, - 0xeb, 0x98, 0x9e, 0x71, 0x56, 0x99, 0x0d, 0xdd, 0x09, 0x4a, 0xdb, 0xc9, - 0xcc, 0xfc, 0x62, 0x31, 0x57, 0x2e, 0x7b, 0xa2, 0x9b, 0x58, 0xf4, 0xa2, - 0x9d, 0x52, 0xa9, 0xb5, 0x4d, 0xa6, 0x2b, 0x24, 0xbe, 0x42, 0xf6, 0xa7, - 0xe7, 0xf2, 0xd9, 0xc8, 0xde, 0x6a, 0x84, 0x35, 0x8a, 0xb4, 0xf1, 0x1e, - 0x92, 0x62, 0xa0, 0x55, 0xe9, 0xcd, 0x64, 0x17, 0x11, 0xe3, 0x28, 0xdc, - 0x16, 0x37, 0x6c, 0xc0, 0xf5, 0xf3, 0x2f, 0x76, 0xd6, 0xa1, 0x63, 0x49, - 0x3f, 0x74, 0xf8, 0x78, 0x38, 0x0d, 0x3b, 0x7f, 0xf7, 0xd7, 0x9d, 0x7e, - 0x65, 0x25, 0x8a, 0x30, 0xe7, 0x07, 0xed, 0xdf, 0x55, 0x21, 0x9e, 0xf0, - 0x04, 0xb4, 0xf2, 0xf7, 0x5d, 0x4c, 0x67, 0x1f, 0xa2, 0x6f, 0xfd, 0xe8, - 0x24, 0xf0, 0xac, 0x7c, 0x6d, 0x2b, 0x3b, 0x93, 0xa9, 0x7f, 0x88, 0xa6, - 0xaa, 0xbe, 0x70, 0xa1, 0xdd, 0x2f, 0xb2, 0x37, 0x13, 0x85, 0xa6, 0xd3, - 0x1d, 0x71, 0x2d, 0x9d, 0x77, 0x0f, 0x82, 0x9a, 0x9e, 0x57, 0x49, 0xae, - 0x94, 0xce, 0x8b, 0x27, 0xcf, 0x64, 0xe8, 0x2b, 0xc0, 0x20, 0x0f, 0x05, - 0x22, 0x34, 0x1e, 0x19, 0x94, 0x6a, 0xe1, 0xbe, 0xa6, 0x36, 0xc9, 0x44, - 0xa5, 0x4a, 0x2c, 0x85, 0x2f, 0xfc, 0xdd, 0x70, 0xa1, 0xbf, 0xcf, 0x70, - 0x2c, 0x78, 0xb4, 0xe1, 0x76, 0x89, 0x12, 0xe0, 0x4d, 0xd9, 0xf0, 0x1d, - 0x77, 0xac, 0xc5, 0xa1, 0x5b, 0x5e, 0x58, 0x0a, 0xd3, 0x64, 0x61, 0xce, - 0x36, 0x2c, 0x7e, 0x8a, 0x6d, 0xd9, 0xe7, 0x90, 0x0a, 0x47, 0x30, 0xca, - 0xf0, 0x90, 0x77, 0x69, 0xb8, 0x00, 0x90, 0xa5, 0xdc, 0x51, 0x30, 0x94, - 0xc9, 0xac, 0xdc, 0xc7, 0x9c, 0xc7, 0x5b, 0x02, 0x82, 0x01, 0x01, 0x00, - 0xb0, 0xe4, 0x66, 0x6e, 0x56, 0x9f, 0x7c, 0x0c, 0xf7, 0x9d, 0xd7, 0x24, - 0x77, 0xdf, 0x01, 0x8d, 0xbb, 0x89, 0xea, 0xb9, 0x81, 0x6e, 0xbd, 0x03, - 0x4b, 0xa1, 0xc1, 0xe3, 0xf9, 0x9f, 0xc4, 0x80, 0x60, 0xd9, 0xc7, 0xd1, - 0x4f, 0x36, 0xcb, 0x75, 0x8b, 0xce, 0xb6, 0x2a, 0x32, 0x99, 0x18, 0xef, - 0x88, 0xdc, 0x80, 0x24, 0x5b, 0x27, 0xa7, 0xe2, 0x99, 0xa1, 0xcf, 0xfa, - 0x85, 0xee, 0x77, 0xd7, 0x1e, 0x77, 0x8f, 0x48, 0x74, 0xc2, 0x74, 0xd3, - 0xae, 0x02, 0x0f, 0x7c, 0x3a, 0xfa, 0x0c, 0xf9, 0x79, 0x6b, 0x7f, 0xb9, - 0xe5, 0x64, 0xa7, 0x07, 0xd1, 0x8e, 0x7a, 0xb6, 0x35, 0x30, 0xe4, 0x49, - 0x57, 0xf1, 0xeb, 0x83, 0xed, 0x69, 0xa2, 0xc6, 0x4f, 0x2c, 0x57, 0xd0, - 0x14, 0x6e, 0x26, 0x6b, 0x2b, 0x0e, 0x3f, 0xac, 0x9d, 0x86, 0xd2, 0x00, - 0xbf, 0x40, 0x41, 0xd7, 0x25, 0x38, 0x80, 0x3c, 0x91, 0x26, 0x96, 0xfa, - 0x5b, 0x46, 0xeb, 0x8a, 0x73, 0xec, 0x87, 0xfa, 0x05, 0xeb, 0x43, 0x9e, - 0x11, 0xec, 0xe7, 0xf0, 0x5e, 0x1b, 0xfe, 0x4b, 0x67, 0xd4, 0xa8, 0xf4, - 0x97, 0x15, 0x2c, 0x99, 0xd4, 0x94, 0xce, 0x17, 0x4d, 0xb7, 0x0d, 0xe6, - 0xe0, 0x1a, 0x92, 0x7d, 0x8a, 0x86, 0x7b, 0xae, 0x80, 0x18, 0x19, 0xd6, - 0x1d, 0x45, 0x8f, 0xf1, 0x24, 0x67, 0x25, 0xee, 0xd5, 0x9e, 0xbc, 0xb4, - 0x08, 0x64, 0xb5, 0x19, 0x69, 0x6b, 0xcd, 0x84, 0x05, 0x83, 0xb1, 0xed, - 0x5c, 0x06, 0xa5, 0x63, 0x85, 0x7b, 0x34, 0xb9, 0xfc, 0x5c, 0xe4, 0x23, - 0x75, 0xdd, 0x9b, 0x3e, 0x89, 0xc3, 0x47, 0x38, 0x5c, 0x68, 0xe9, 0x58, - 0x86, 0xbf, 0x55, 0xb3, 0x07, 0x8b, 0x1f, 0xe7, 0xb2, 0x67, 0x16, 0xa3, - 0x7e, 0x93, 0x11, 0xe6, 0x20, 0x49, 0xcb, 0xa8, 0xf0, 0x9b, 0xb6, 0x43, - 0x78, 0x0b, 0xa5, 0xad, 0x02, 0x82, 0x01, 0x00, 0x0a, 0x1c, 0x7d, 0x20, - 0x16, 0xf5, 0xcf, 0xaf, 0xa6, 0xeb, 0xb7, 0x0e, 0xee, 0xf5, 0x82, 0xe2, - 0x22, 0x18, 0xa8, 0x80, 0xe8, 0x12, 0x59, 0xd6, 0x3b, 0x45, 0x2f, 0x24, - 0xd1, 0x7f, 0xc6, 0x38, 0x72, 0xd4, 0x99, 0xe2, 0x5c, 0xec, 0x14, 0xc2, - 0xc6, 0xe2, 0x2f, 0xad, 0x96, 0xcb, 0x78, 0x5d, 0xf1, 0x07, 0xd9, 0xf1, - 0x77, 0x54, 0x1a, 0x05, 0xcd, 0x9d, 0x26, 0xdf, 0x19, 0x3a, 0x58, 0x8c, - 0x1d, 0xde, 0xa5, 0x76, 0xa5, 0x3a, 0x11, 0xba, 0x22, 0xf3, 0xc0, 0x9e, - 0x01, 0xd1, 0x48, 0xef, 0x8f, 0xe5, 0x34, 0xc5, 0x01, 0x8d, 0xf5, 0x4a, - 0x75, 0xc9, 0x73, 0x08, 0x55, 0x63, 0xd4, 0xd8, 0xd1, 0x60, 0x48, 0xa4, - 0x80, 0x51, 0x1a, 0x17, 0xfb, 0x32, 0x08, 0x65, 0x74, 0x83, 0x88, 0x8b, - 0x35, 0xb5, 0xfa, 0x70, 0xb4, 0xd4, 0x45, 0xc9, 0x1b, 0xe7, 0x59, 0xf4, - 0x1a, 0x41, 0xd8, 0x98, 0xcd, 0x56, 0x1e, 0xaf, 0x05, 0x4e, 0x7a, 0x2f, - 0xe7, 0xba, 0xf3, 0x0d, 0x3e, 0xae, 0x47, 0x9d, 0x4b, 0x02, 0x6b, 0x73, - 0x8b, 0xe2, 0x53, 0x3a, 0x0e, 0x42, 0xfc, 0x62, 0x6f, 0xaa, 0x7f, 0x02, - 0xa7, 0x6a, 0xd4, 0x6c, 0x2d, 0x25, 0xe7, 0xf6, 0x34, 0xf5, 0x8d, 0xbf, - 0x0d, 0x81, 0xc7, 0x0d, 0x73, 0xfe, 0x79, 0xf2, 0x8c, 0xe3, 0xff, 0x5f, - 0x03, 0xdb, 0x2a, 0x07, 0x18, 0x63, 0xc1, 0xfb, 0xf0, 0x6e, 0xa9, 0x2a, - 0x4c, 0x74, 0x51, 0xd4, 0x51, 0x6c, 0x98, 0x62, 0x94, 0x25, 0x23, 0xfd, - 0xdb, 0x13, 0x6e, 0x6a, 0x93, 0xc4, 0x62, 0x8f, 0x2a, 0x8e, 0x3b, 0x44, - 0xa5, 0x22, 0x2b, 0x5b, 0xe6, 0xa0, 0x14, 0x02, 0x03, 0xd1, 0xdc, 0x2b, - 0xbb, 0x82, 0x04, 0x7c, 0x87, 0x22, 0xb4, 0xa4, 0x5a, 0x6c, 0x2c, 0xfa, - 0xdc, 0x56, 0x9f, 0x4c, 0x71, 0xb0, 0x6d, 0xcc, 0x3f, 0x99, 0x8c, 0xc9, - 0x02, 0x82, 0x01, 0x00, 0x45, 0xee, 0xc9, 0x30, 0x7a, 0xb0, 0xb4, 0x5d, - 0x16, 0xdb, 0xaa, 0x6d, 0x59, 0x2a, 0xd6, 0x99, 0x42, 0x4d, 0x71, 0x72, - 0x6c, 0xf2, 0x3e, 0xa8, 0xcf, 0xb5, 0xfd, 0x4b, 0x2c, 0x9e, 0x1b, 0x74, - 0x14, 0x69, 0x9c, 0xcc, 0x2f, 0x69, 0x52, 0x4c, 0x66, 0x16, 0x44, 0xdb, - 0x2b, 0x51, 0xd6, 0x1f, 0x83, 0x5f, 0x19, 0x2d, 0x10, 0x5a, 0x6d, 0x71, - 0xdc, 0x97, 0xdd, 0x58, 0x08, 0x72, 0x20, 0xf0, 0xe2, 0xf5, 0x32, 0x20, - 0xfe, 0xfb, 0x51, 0x1a, 0x18, 0x6b, 0x19, 0xc5, 0xae, 0xcf, 0x3c, 0xb6, - 0x17, 0x81, 0x02, 0x20, 0x56, 0xf8, 0xe4, 0x21, 0x63, 0xaa, 0x58, 0xd1, - 0xc3, 0xf5, 0x13, 0x53, 0x9f, 0xa4, 0xa4, 0x00, 0x98, 0x1a, 0x5f, 0x12, - 0x46, 0x1d, 0xee, 0x17, 0x3a, 0xf2, 0xad, 0x1f, 0x11, 0x3b, 0xfc, 0x95, - 0xdf, 0x6b, 0xe6, 0x44, 0xb6, 0xfd, 0x67, 0x99, 0xa2, 0xf9, 0xbb, 0x52, - 0xda, 0xb9, 0xfb, 0xb3, 0xb2, 0xf1, 0xf2, 0x34, 0x96, 0xb4, 0x77, 0xec, - 0xe8, 0x63, 0xac, 0x4c, 0xaf, 0x83, 0x8f, 0x6e, 0x7b, 0x3d, 0x33, 0xfc, - 0x83, 0x35, 0x90, 0xa0, 0xe5, 0x96, 0xd7, 0x50, 0x80, 0xf0, 0xab, 0xec, - 0xed, 0x1d, 0x36, 0xdf, 0xf3, 0xe1, 0xba, 0xe0, 0x04, 0xef, 0x1a, 0x54, - 0x34, 0x65, 0x06, 0xd4, 0x02, 0x2d, 0x2d, 0xec, 0x53, 0x9f, 0x0d, 0x53, - 0xaf, 0x42, 0x51, 0x74, 0x6b, 0xc1, 0x45, 0x35, 0x0f, 0xa6, 0x66, 0x48, - 0x46, 0xf9, 0x85, 0x8f, 0x90, 0x69, 0x6e, 0xb4, 0xbf, 0x26, 0x72, 0x77, - 0x90, 0x76, 0xb1, 0x1f, 0x1f, 0x7e, 0x75, 0x96, 0x81, 0x83, 0x53, 0x67, - 0x05, 0x78, 0x5f, 0x4e, 0x8d, 0xaa, 0x4e, 0xcb, 0x58, 0x1d, 0x27, 0xbe, - 0x9a, 0x2f, 0x07, 0xd4, 0x4c, 0x15, 0x19, 0x58, 0x7d, 0x14, 0xa0, 0x38, - 0xf0, 0x06, 0x41, 0x89, 0x73, 0xe5, 0xa4, 0x37 -}; + "\x30\x82\x09\x29\x02\x01\x00\x02\x82\x02\x01\x00\xc8\xf2\xdb\x39" + "\xad\xf4\x43\x97\xa2\x6d\x85\x2c\x17\x14\x26\x25\xe9\x8f\xb8\x71" + "\x3c\x58\x5b\x2d\x18\x0f\xad\x76\xa7\xfe\x8f\x46\x4c\x67\xc3\x1e" + "\x70\xe0\x82\xd3\x77\x67\x9d\x6d\x76\xa2\xca\x79\x70\xd2\xae\xbe" + "\x21\xa6\xa7\x42\xea\x30\xcb\x96\x15\xa6\x21\x62\x66\xa5\xdd\xff" + "\x23\x78\xc9\xe0\x9f\x73\xb8\x08\x1e\x0e\x49\x85\x8d\xdf\x55\x24" + "\x42\xc1\x4b\xc9\xde\x03\xa0\xcf\xc7\xaf\x25\xfd\x6a\xe8\xea\xfc" + "\xd3\x09\x85\xdb\x6b\x9e\x4a\x8d\x71\x91\xe9\x84\xa7\x75\x6d\xdd" + "\x2e\x60\x8c\xaf\x30\xfa\xdd\x1e\x0d\x04\x5c\x7b\xc2\x35\x0d\xee" + "\x5b\xe5\x62\x81\xb9\x98\xf1\xce\x3f\x92\x59\x1f\xd0\xe4\x17\x48" + "\xfb\xfe\xa0\xb3\x2c\x7c\x01\xc0\x19\x56\xa1\x20\x08\x06\x7d\x70" + "\xf2\x2f\xb2\xad\x44\xc2\xe4\x5b\x84\x2b\x98\x06\x87\xaf\x54\x2b" + "\xb7\xe4\xfe\x53\x2f\xf2\xd7\xb4\x34\x4d\x46\xdf\x44\x2e\x72\x04" + "\xd7\x34\x3e\xde\xbf\x55\x74\x7f\x3e\xd4\xc3\x3d\x1f\x7c\x24\xf2" + "\xed\x4f\x38\x1d\xf4\xb2\x47\x5e\xe9\x2c\x23\xf3\xdd\xbb\x16\xd9" + "\x1c\xba\x53\x1a\x1c\xf1\x02\xf1\x8e\xec\x79\x5b\xf9\x55\x21\x66" + "\x12\x6f\x9e\xf0\x9e\x3f\xdc\xbe\xd6\x31\x35\xc2\xf2\x78\xb6\x0a" + "\x9b\x22\xa3\xa6\x9d\xd3\xf5\x4f\x05\x49\x00\xc4\xc2\xc2\x87\x43" + "\x06\xfc\x43\x3c\xda\xf6\xfa\xbd\xf7\x99\xfb\xd5\x64\x6f\x69\xd9" + "\x4d\xb9\xc5\x1a\x07\xd6\xdf\x40\xb7\x4a\x6b\x16\xc8\x2c\x23\x5f" + "\xe2\xee\x7c\x66\xdd\x3b\x7c\x80\x40\x9a\xb9\xd8\x99\xf7\xde\x71" + "\x3d\xf7\x35\x86\x0f\x6b\xf9\x01\xe9\x53\xf9\x17\xcf\x1f\x6e\xf8" + "\xac\xfa\x2f\x5f\x33\x13\x33\xfa\xf1\xcf\x7d\x6b\xb9\xd6\xa3\x68" + "\x16\x84\x60\x89\x6f\x2c\xc8\xe7\xf2\xe0\xc9\x7f\x84\xce\xe9\x45" + "\x18\x96\x9a\x99\xac\x0e\x0e\x61\xea\x33\xbf\x3d\xb1\x8b\x92\x9e" + "\xdf\xc6\x75\x66\x56\x7a\x9a\xa9\x9b\xd8\x77\x64\xad\xf6\x41\xc4" + "\x32\x3b\x8e\xe9\x90\x55\xfe\xe3\x0b\x2c\x43\x37\xaa\x8a\x79\x38" + "\xb4\x89\x9b\x2d\xac\xe7\x6e\x3f\x23\xb3\x30\xa2\x84\x21\x97\x8d" + "\x2d\x02\x14\xac\xfa\x67\x4b\x6c\xbc\x33\xf5\x89\x88\x8a\x57\xdd" + "\x96\x9c\x6a\x5a\x06\x62\x33\xb1\xe0\xaa\x70\xc8\x05\x81\x82\x62" + "\x3d\xa0\x4c\xdf\x71\xa8\x7e\x7d\xb3\xc6\x70\xf1\x60\xac\xd6\x46" + "\xd8\x85\xb7\x6b\x5f\xb7\xa1\x86\xb6\xf5\xca\xf6\xa2\x8d\xe9\x78" + "\x37\x13\x1d\xe0\xd3\x13\x9f\x0e\x20\x2c\x26\x87\x02\x03\x01\x00" + "\x01\x02\x82\x02\x00\x47\x8f\xcd\x28\x86\x5d\x85\xb0\xbb\x84\x7b" + "\x37\x8f\x64\x7a\x8d\x67\xd6\xe9\xdd\x51\x9b\x39\xa5\x1e\x7b\x7e" + "\xcf\xd1\xd5\xe2\xda\x2b\x1d\x8c\xac\x0b\x90\xb8\xa6\x6c\x50\x77" + "\x0c\xe3\x81\xe7\xcf\x45\xb1\x91\xcf\x5e\x16\x86\x5c\x5b\x20\x53" + "\x70\x38\x77\x78\x4e\x1d\xb6\x16\x0f\xe5\x66\xff\xa5\xc1\xc3\x29" + "\x17\xa2\xf4\x7d\x94\x55\x48\xe2\x7e\x4e\x53\x9e\x14\xde\xbe\xb6" + "\x07\x28\xda\xa4\x11\xd2\x7f\xee\x27\x69\x54\x6b\xda\x0f\x42\x48" + "\xd4\x84\x4c\x6d\x37\xf3\x96\xeb\x30\x28\x72\xf3\xc6\xf4\x0f\x72" + "\xad\x5f\xff\x5c\x9c\x2a\x36\x50\xa6\xc1\x0d\x38\x7e\x70\x45\x1a" + "\x5f\xd3\xdd\xdf\x65\x68\x33\xc2\x63\x18\x72\xbe\x71\xf0\x76\x9c" + "\xfc\xf7\x49\x15\x8a\x5d\xb1\x49\xfc\xee\x12\xb4\x73\xe6\x17\xed" + "\xd0\xf5\x89\xbc\xd3\x1e\x80\xfe\xdd\xae\xd8\x9b\x05\xae\xfe\xb1" + "\x78\x98\x63\xa8\xc8\x9b\xf4\x5a\x60\x84\xef\x33\x30\x8a\x3c\xf9" + "\x86\xd3\x2e\x5b\xf5\x29\x80\x41\x7c\x4d\xac\xb7\x94\x5b\x6f\x1d" + "\xe1\x9b\xf2\x3f\x3f\x7a\x88\x45\x03\xbe\xaa\x50\x2b\xed\x80\x9b" + "\x06\xc1\x5a\x4f\x81\xc4\x92\x5f\x99\x85\x19\x41\x25\xf9\x85\x4e" + "\xac\x9b\x84\xdc\xda\xd4\xeb\xae\xc5\xe5\xdc\x00\x09\x15\x75\x85" + "\x4b\xf0\xe3\x31\x87\x3d\xe5\x8e\xf1\x00\x20\xc7\x9b\xa4\xf2\x70" + "\x4e\x6e\x80\xe2\xbc\x35\x76\xae\xca\xc8\xb1\x47\xe4\x26\x90\x57" + "\xad\x15\xa4\x54\x71\x33\xb1\x71\x98\x6d\x96\xc4\x8d\xc7\x34\xa9" + "\x32\x6a\xef\xd8\x0a\x86\x32\xe2\x89\x0a\xd1\xd8\x0a\x6a\x84\x14" + "\x77\xde\x3a\xb9\xd3\xda\xae\x17\xf8\x0c\x63\xa5\x41\x56\x58\xa8" + "\xc4\x84\xd1\xb2\xf8\xe3\x1d\xbf\x91\xf7\xb4\x46\xd6\xc7\x53\xb2" + "\xeb\x89\x28\x64\x68\x80\xf4\x72\xf8\xd7\x50\xab\x27\x70\x5c\x4d" + "\x20\x43\x8c\x52\xa0\x55\xef\xff\xfb\x46\x8c\x62\x14\x97\xd0\x55" + "\x76\x2c\xe8\xe8\xa5\x96\x5d\x7c\x0d\x01\xcf\xba\x32\x2e\x8c\x16" + "\x40\x66\x46\x0d\x50\x38\x2a\x65\x14\xe0\x34\xbe\x5d\xeb\xbe\xd6" + "\xfe\x8b\xa3\x6a\x11\x8b\xda\xbf\x7a\x55\x4a\x34\xbf\x9b\x3d\x23" + "\xd3\x6e\x9a\x3f\x4b\x60\x58\x84\x31\x2b\xe8\x92\xed\x14\x57\x14" + "\x08\xae\x21\x0f\x0a\xd2\x9c\x75\x2f\x2d\xd0\x14\xb5\x14\xfa\xa1" + "\x1d\xef\xdf\x2a\xf8\x67\xc8\xb8\x9f\x1d\x89\xe9\xe5\xa8\x44\x4f" + "\x3a\xc4\xd5\xdb\xfa\xb2\x8b\x68\x66\xbc\xdf\xb3\x68\x5b\x2c\x92" + "\xf8\x49\xc3\x2d\xf9\x02\x82\x01\x01\x00\xcf\xdc\x9b\x30\x30\x03" + "\x1a\x74\xce\x7b\xd2\x9a\x04\xda\x91\x27\xe8\x74\x7c\x1c\x4f\xeb" + "\x98\x9e\x71\x56\x99\x0d\xdd\x09\x4a\xdb\xc9\xcc\xfc\x62\x31\x57" + "\x2e\x7b\xa2\x9b\x58\xf4\xa2\x9d\x52\xa9\xb5\x4d\xa6\x2b\x24\xbe" + "\x42\xf6\xa7\xe7\xf2\xd9\xc8\xde\x6a\x84\x35\x8a\xb4\xf1\x1e\x92" + "\x62\xa0\x55\xe9\xcd\x64\x17\x11\xe3\x28\xdc\x16\x37\x6c\xc0\xf5" + "\xf3\x2f\x76\xd6\xa1\x63\x49\x3f\x74\xf8\x78\x38\x0d\x3b\x7f\xf7" + "\xd7\x9d\x7e\x65\x25\x8a\x30\xe7\x07\xed\xdf\x55\x21\x9e\xf0\x04" + "\xb4\xf2\xf7\x5d\x4c\x67\x1f\xa2\x6f\xfd\xe8\x24\xf0\xac\x7c\x6d" + "\x2b\x3b\x93\xa9\x7f\x88\xa6\xaa\xbe\x70\xa1\xdd\x2f\xb2\x37\x13" + "\x85\xa6\xd3\x1d\x71\x2d\x9d\x77\x0f\x82\x9a\x9e\x57\x49\xae\x94" + "\xce\x8b\x27\xcf\x64\xe8\x2b\xc0\x20\x0f\x05\x22\x34\x1e\x19\x94" + "\x6a\xe1\xbe\xa6\x36\xc9\x44\xa5\x4a\x2c\x85\x2f\xfc\xdd\x70\xa1" + "\xbf\xcf\x70\x2c\x78\xb4\xe1\x76\x89\x12\xe0\x4d\xd9\xf0\x1d\x77" + "\xac\xc5\xa1\x5b\x5e\x58\x0a\xd3\x64\x61\xce\x36\x2c\x7e\x8a\x6d" + "\xd9\xe7\x90\x0a\x47\x30\xca\xf0\x90\x77\x69\xb8\x00\x90\xa5\xdc" + "\x51\x30\x94\xc9\xac\xdc\xc7\x9c\xc7\x5b\x02\x82\x01\x01\x00\xf7" + "\x7c\x65\xc6\x43\x0b\x60\x60\xfd\xfc\xe0\xcd\x37\xfc\x98\xfb\x6b" + "\xb8\x4f\x8b\xdb\x79\x0c\x52\xeb\x62\xd5\x44\x67\x4f\x67\x11\x02" + "\x5b\x37\x2f\xcc\x31\x17\x44\x42\x96\x76\xc8\x5d\x46\x1b\xd7\xad" + "\x7a\x4c\x16\xdc\xab\x1d\xe9\x64\xd3\xc4\xe4\x46\x76\x05\xb4\x09" + "\x8b\xb3\xba\xca\x68\xba\xf0\x50\x7a\x24\x33\xc1\xb5\xf2\xb7\xa0" + "\xd8\xfd\xbd\x57\xe0\x32\x15\x9c\xb0\xc3\x74\xd0\xb1\xe8\x26\xd8" + "\xd1\x22\x56\x0e\xd7\x39\xe6\xed\x0e\x62\x4c\x05\x37\x05\x7d\x19" + "\x10\xa7\xf2\x36\x76\x34\xee\xa7\xc0\x0a\xf8\x78\x2f\x8d\xd4\x68" + "\x44\xd1\x19\x39\x00\x8b\xa6\x9c\x48\xcb\x4a\xe0\x53\x78\x8a\x0e" + "\x52\xe4\xb2\xb2\x6a\x19\xd8\xb2\x29\x54\xc3\xb7\x0f\xdd\x04\xa5" + "\x73\xec\x53\x8c\x80\xd7\x9e\x46\x14\xba\x0d\xa2\xaa\xf2\xc6\x42" + "\xa7\xbb\xbe\x16\x21\xb9\xe0\x4b\x28\x3a\xec\x9a\x1f\x96\xff\x9b" + "\x67\x34\x78\x81\xec\x11\x8d\x86\x01\xdd\xb2\x32\xf7\x9b\xa1\x29" + "\xfd\xf7\xd7\x7a\x1f\x24\x86\x62\xcd\xa2\x73\x27\x87\x1e\x3f\x45" + "\xc1\xef\xf9\x2e\x1b\xa5\x0d\x69\x9f\xc7\x70\xea\x55\xd7\x09\x7d" + "\x0f\x65\xcd\xe5\xb6\x6d\xd4\x77\x7d\xe1\xaf\xaf\xe6\x31\x45\x02" + "\x82\x01\x00\x0a\x1c\x7d\x20\x16\xf5\xcf\xaf\xa6\xeb\xb7\x0e\xee" + "\xf5\x82\xe2\x22\x18\xa8\x80\xe8\x12\x59\xd6\x3b\x45\x2f\x24\xd1" + "\x7f\xc6\x38\x72\xd4\x99\xe2\x5c\xec\x14\xc2\xc6\xe2\x2f\xad\x96" + "\xcb\x78\x5d\xf1\x07\xd9\xf1\x77\x54\x1a\x05\xcd\x9d\x26\xdf\x19" + "\x3a\x58\x8c\x1d\xde\xa5\x76\xa5\x3a\x11\xba\x22\xf3\xc0\x9e\x01" + "\xd1\x48\xef\x8f\xe5\x34\xc5\x01\x8d\xf5\x4a\x75\xc9\x73\x08\x55" + "\x63\xd4\xd8\xd1\x60\x48\xa4\x80\x51\x1a\x17\xfb\x32\x08\x65\x74" + "\x83\x88\x8b\x35\xb5\xfa\x70\xb4\xd4\x45\xc9\x1b\xe7\x59\xf4\x1a" + "\x41\xd8\x98\xcd\x56\x1e\xaf\x05\x4e\x7a\x2f\xe7\xba\xf3\x0d\x3e" + "\xae\x47\x9d\x4b\x02\x6b\x73\x8b\xe2\x53\x3a\x0e\x42\xfc\x62\x6f" + "\xaa\x7f\x02\xa7\x6a\xd4\x6c\x2d\x25\xe7\xf6\x34\xf5\x8d\xbf\x0d" + "\x81\xc7\x0d\x73\xfe\x79\xf2\x8c\xe3\xff\x5f\x03\xdb\x2a\x07\x18" + "\x63\xc1\xfb\xf0\x6e\xa9\x2a\x4c\x74\x51\xd4\x51\x6c\x98\x62\x94" + "\x25\x23\xfd\xdb\x13\x6e\x6a\x93\xc4\x62\x8f\x2a\x8e\x3b\x44\xa5" + "\x22\x2b\x5b\xe6\xa0\x14\x02\x03\xd1\xdc\x2b\xbb\x82\x04\x7c\x87" + "\x22\xb4\xa4\x5a\x6c\x2c\xfa\xdc\x56\x9f\x4c\x71\xb0\x6d\xcc\x3f" + "\x99\x8c\xc9\x02\x82\x01\x01\x00\xb0\xe4\x66\x6e\x56\x9f\x7c\x0c" + "\xf7\x9d\xd7\x24\x77\xdf\x01\x8d\xbb\x89\xea\xb9\x81\x6e\xbd\x03" + "\x4b\xa1\xc1\xe3\xf9\x9f\xc4\x80\x60\xd9\xc7\xd1\x4f\x36\xcb\x75" + "\x8b\xce\xb6\x2a\x32\x99\x18\xef\x88\xdc\x80\x24\x5b\x27\xa7\xe2" + "\x99\xa1\xcf\xfa\x85\xee\x77\xd7\x1e\x77\x8f\x48\x74\xc2\x74\xd3" + "\xae\x02\x0f\x7c\x3a\xfa\x0c\xf9\x79\x6b\x7f\xb9\xe5\x64\xa7\x07" + "\xd1\x8e\x7a\xb6\x35\x30\xe4\x49\x57\xf1\xeb\x83\xed\x69\xa2\xc6" + "\x4f\x2c\x57\xd0\x14\x6e\x26\x6b\x2b\x0e\x3f\xac\x9d\x86\xd2\x00" + "\xbf\x40\x41\xd7\x25\x38\x80\x3c\x91\x26\x96\xfa\x5b\x46\xeb\x8a" + "\x73\xec\x87\xfa\x05\xeb\x43\x9e\x11\xec\xe7\xf0\x5e\x1b\xfe\x4b" + "\x67\xd4\xa8\xf4\x97\x15\x2c\x99\xd4\x94\xce\x17\x4d\xb7\x0d\xe6" + "\xe0\x1a\x92\x7d\x8a\x86\x7b\xae\x80\x18\x19\xd6\x1d\x45\x8f\xf1" + "\x24\x67\x25\xee\xd5\x9e\xbc\xb4\x08\x64\xb5\x19\x69\x6b\xcd\x84" + "\x05\x83\xb1\xed\x5c\x06\xa5\x63\x85\x7b\x34\xb9\xfc\x5c\xe4\x23" + "\x75\xdd\x9b\x3e\x89\xc3\x47\x38\x5c\x68\xe9\x58\x86\xbf\x55\xb3" + "\x07\x8b\x1f\xe7\xb2\x67\x16\xa3\x7e\x93\x11\xe6\x20\x49\xcb\xa8" + "\xf0\x9b\xb6\x43\x78\x0b\xa5\xad\x02\x82\x01\x01\x00\x95\x20\x2d" + "\xad\xa2\x02\xff\x9d\x01\xd5\x50\x81\xf7\x3d\xef\xe5\x3f\x9d\xfc" + "\x30\xf1\x09\x1b\xc7\x48\xdf\x39\xe0\x48\xea\xe9\x7c\xad\x1f\x3e" + "\x62\x43\x44\x98\xeb\x75\x1c\xfb\x24\x7a\x93\x80\x29\x69\x52\xa1" + "\x6a\xa1\xeb\xf9\x7b\xf3\xf9\xdb\x30\x72\xfa\x71\x4f\x2a\xe4\x83" + "\xfb\x41\x6b\x69\x76\x3a\x33\xec\x24\x0b\xd0\x9c\xc4\xc9\x74\xb7" + "\x8f\xca\xbc\x02\x75\x38\x70\x94\xfa\x44\xa2\x2f\xd7\xc1\x2e\x63" + "\x63\x76\xc9\x72\x5c\x88\xcf\x32\x4e\x92\x27\xdf\x6d\x8f\x6d\xe0" + "\xd6\x56\xed\xd9\x1b\x22\x41\x07\x60\x2f\x77\x9a\x21\x43\xab\x13" + "\x7e\x78\x7f\x64\x7b\xab\xe0\xac\x2c\xd0\x2c\x07\xe9\xb1\x7d\xb3" + "\xef\x7f\x4e\x31\x82\xb6\x0a\x9b\x24\x90\x82\x53\x73\xa7\x1f\x99" + "\x14\xb5\x6f\xa1\x50\x71\x05\x4f\x43\xcd\xa2\xe3\x4c\xe9\x1c\x2a" + "\xd2\x5c\xbe\xf7\x2d\x51\xcd\xb0\x75\xdc\x4d\x9b\x3c\xd2\x64\xe7" + "\x32\x02\x33\xb2\xfe\xd7\x58\xa2\x87\xaa\xa6\x88\xa6\x92\x69\x41" + "\xc2\x1f\x4a\xf5\x24\x7c\x2d\x14\xf5\x3e\x7d\x0e\x85\x21\x32\x78" + "\xfe\x82\x12\x34\xb9\xaf\xee\x17\x9b\x62\xc7\x55\xdd\x46\x12\xa4" + "\x5d\x19\x42\x85\x64\xa4\x9f\x36\x94\xbb\x99\xae\x3f"; diff --git a/testkeys/RSA/4096_RSA_KEY.pem b/testkeys/RSA/4096_RSA_KEY.pem index f2dc1cb..3a817ca 100644 --- a/testkeys/RSA/4096_RSA_KEY.pem +++ b/testkeys/RSA/4096_RSA_KEY.pem @@ -1,5 +1,5 @@ -----BEGIN RSA PRIVATE KEY----- -MIIJKAIBAAKCAgEAyPLbOa30Q5eibYUsFxQmJemPuHE8WFstGA+tdqf+j0ZMZ8Me +MIIJKQIBAAKCAgEAyPLbOa30Q5eibYUsFxQmJemPuHE8WFstGA+tdqf+j0ZMZ8Me cOCC03dnnW12osp5cNKuviGmp0LqMMuWFaYhYmal3f8jeMngn3O4CB4OSYWN31Uk QsFLyd4DoM/HryX9aujq/NMJhdtrnkqNcZHphKd1bd0uYIyvMPrdHg0EXHvCNQ3u W+VigbmY8c4/klkf0OQXSPv+oLMsfAHAGVahIAgGfXDyL7KtRMLkW4QrmAaHr1Qr @@ -20,32 +20,32 @@ Tm6A4rw1dq7KyLFH5CaQV60VpFRxM7FxmG2WxI3HNKkyau/YCoYy4okK0dgKaoQU d946udParhf4DGOlQVZYqMSE0bL44x2/kfe0RtbHU7LriShkaID0cvjXUKsncFxN IEOMUqBV7//7RoxiFJfQVXYs6Oilll18DQHPujIujBZAZkYNUDgqZRTgNL5d677W /oujahGL2r96VUo0v5s9I9Numj9LYFiEMSvoku0UVxQIriEPCtKcdS8t0BS1FPqh -He/fKvhnyLifHYnp5ahETzrE1dv6sotoZrzfs2hbLJL4ScMt+QKCAQEA93xlxkML -YGD9/ODNN/yY+2u4T4vbeQxS62LVRGdPZxECWzcvzDEXREKWdshdRhvXrXpMFtyr -Helk08TkRnYFtAmLs7rKaLrwUHokM8G18reg2P29V+AyFZyww3TQsegm2NEiVg7X -OebtDmJMBTcFfRkQp/I2djTup8AK+HgvjdRoRNEZOQCLppxIy0rgU3iKDlLksrJq -GdiyKVTDtw/dBKVz7FOMgNeeRhS6DaKq8sZCp7u+FiG54EsoOuyaH5b/m2c0eIHs -EY2GAd2yMveboSn999d6HySGYs2icyeHHj9Fwe/5LhulDWmfx3DqVdcJfQ9lzeW2 -bdR3feGvr+YxRQKCAQEAz9ybMDADGnTOe9KaBNqRJ+h0fBxP65iecVaZDd0JStvJ -zPxiMVcue6KbWPSinVKptU2mKyS+Qvan5/LZyN5qhDWKtPEekmKgVenNZBcR4yjc -FjdswPXzL3bWoWNJP3T4eDgNO3/3151+ZSWKMOcH7d9VIZ7wBLTy911MZx+ib/3o -JPCsfG0rO5Opf4imqr5wod0vsjcThabTHXEtnXcPgpqeV0mulM6LJ89k6CvAIA8F -IjQeGZRq4b6mNslEpUoshS/83XChv89wLHi04XaJEuBN2fAdd6zFoVteWArTZGHO -Nix+im3Z55AKRzDK8JB3abgAkKXcUTCUyazcx5zHWwKCAQEAsORmblaffAz3ndck -d98BjbuJ6rmBbr0DS6HB4/mfxIBg2cfRTzbLdYvOtioymRjviNyAJFsnp+KZoc/6 -he531x53j0h0wnTTrgIPfDr6DPl5a3+55WSnB9GOerY1MORJV/Hrg+1posZPLFfQ -FG4maysOP6ydhtIAv0BB1yU4gDyRJpb6W0brinPsh/oF60OeEezn8F4b/ktn1Kj0 -lxUsmdSUzhdNtw3m4BqSfYqGe66AGBnWHUWP8SRnJe7Vnry0CGS1GWlrzYQFg7Ht -XAalY4V7NLn8XOQjdd2bPonDRzhcaOlYhr9VsweLH+eyZxajfpMR5iBJy6jwm7ZD -eAulrQKCAQAKHH0gFvXPr6brtw7u9YLiIhiogOgSWdY7RS8k0X/GOHLUmeJc7BTC -xuIvrZbLeF3xB9nxd1QaBc2dJt8ZOliMHd6ldqU6Eboi88CeAdFI74/lNMUBjfVK -dclzCFVj1NjRYEikgFEaF/syCGV0g4iLNbX6cLTURckb51n0GkHYmM1WHq8FTnov -57rzDT6uR51LAmtzi+JTOg5C/GJvqn8Cp2rUbC0l5/Y09Y2/DYHHDXP+efKM4/9f -A9sqBxhjwfvwbqkqTHRR1FFsmGKUJSP92xNuapPEYo8qjjtEpSIrW+agFAID0dwr -u4IEfIcitKRabCz63FafTHGwbcw/mYzJAoIBAEXuyTB6sLRdFtuqbVkq1plCTXFy -bPI+qM+1/Ussnht0FGmczC9pUkxmFkTbK1HWH4NfGS0QWm1x3JfdWAhyIPDi9TIg -/vtRGhhrGcWuzzy2F4ECIFb45CFjqljRw/UTU5+kpACYGl8SRh3uFzryrR8RO/yV -32vmRLb9Z5mi+btS2rn7s7Lx8jSWtHfs6GOsTK+Dj257PTP8gzWQoOWW11CA8Kvs -7R023/PhuuAE7xpUNGUG1AItLexTnw1Tr0JRdGvBRTUPpmZIRvmFj5BpbrS/JnJ3 -kHaxHx9+dZaBg1NnBXhfTo2qTstYHSe+mi8H1EwVGVh9FKA48AZBiXPlpDc= +He/fKvhnyLifHYnp5ahETzrE1dv6sotoZrzfs2hbLJL4ScMt+QKCAQEAz9ybMDAD +GnTOe9KaBNqRJ+h0fBxP65iecVaZDd0JStvJzPxiMVcue6KbWPSinVKptU2mKyS+ +Qvan5/LZyN5qhDWKtPEekmKgVenNZBcR4yjcFjdswPXzL3bWoWNJP3T4eDgNO3/3 +151+ZSWKMOcH7d9VIZ7wBLTy911MZx+ib/3oJPCsfG0rO5Opf4imqr5wod0vsjcT +habTHXEtnXcPgpqeV0mulM6LJ89k6CvAIA8FIjQeGZRq4b6mNslEpUoshS/83XCh +v89wLHi04XaJEuBN2fAdd6zFoVteWArTZGHONix+im3Z55AKRzDK8JB3abgAkKXc +UTCUyazcx5zHWwKCAQEA93xlxkMLYGD9/ODNN/yY+2u4T4vbeQxS62LVRGdPZxEC +WzcvzDEXREKWdshdRhvXrXpMFtyrHelk08TkRnYFtAmLs7rKaLrwUHokM8G18reg +2P29V+AyFZyww3TQsegm2NEiVg7XOebtDmJMBTcFfRkQp/I2djTup8AK+HgvjdRo +RNEZOQCLppxIy0rgU3iKDlLksrJqGdiyKVTDtw/dBKVz7FOMgNeeRhS6DaKq8sZC +p7u+FiG54EsoOuyaH5b/m2c0eIHsEY2GAd2yMveboSn999d6HySGYs2icyeHHj9F +we/5LhulDWmfx3DqVdcJfQ9lzeW2bdR3feGvr+YxRQKCAQAKHH0gFvXPr6brtw7u +9YLiIhiogOgSWdY7RS8k0X/GOHLUmeJc7BTCxuIvrZbLeF3xB9nxd1QaBc2dJt8Z +OliMHd6ldqU6Eboi88CeAdFI74/lNMUBjfVKdclzCFVj1NjRYEikgFEaF/syCGV0 +g4iLNbX6cLTURckb51n0GkHYmM1WHq8FTnov57rzDT6uR51LAmtzi+JTOg5C/GJv +qn8Cp2rUbC0l5/Y09Y2/DYHHDXP+efKM4/9fA9sqBxhjwfvwbqkqTHRR1FFsmGKU +JSP92xNuapPEYo8qjjtEpSIrW+agFAID0dwru4IEfIcitKRabCz63FafTHGwbcw/ +mYzJAoIBAQCw5GZuVp98DPed1yR33wGNu4nquYFuvQNLocHj+Z/EgGDZx9FPNst1 +i862KjKZGO+I3IAkWyen4pmhz/qF7nfXHnePSHTCdNOuAg98OvoM+Xlrf7nlZKcH +0Y56tjUw5ElX8euD7Wmixk8sV9AUbiZrKw4/rJ2G0gC/QEHXJTiAPJEmlvpbRuuK +c+yH+gXrQ54R7OfwXhv+S2fUqPSXFSyZ1JTOF023DebgGpJ9ioZ7roAYGdYdRY/x +JGcl7tWevLQIZLUZaWvNhAWDse1cBqVjhXs0ufxc5CN13Zs+icNHOFxo6ViGv1Wz +B4sf57JnFqN+kxHmIEnLqPCbtkN4C6WtAoIBAQCVIC2togL/nQHVUIH3Pe/lP538 +MPEJG8dI3zngSOrpfK0fPmJDRJjrdRz7JHqTgClpUqFqoev5e/P52zBy+nFPKuSD ++0FraXY6M+wkC9CcxMl0t4/KvAJ1OHCU+kSiL9fBLmNjdslyXIjPMk6SJ99tj23g +1lbt2RsiQQdgL3eaIUOrE354f2R7q+CsLNAsB+mxfbPvf04xgrYKmySQglNzpx+Z +FLVvoVBxBU9DzaLjTOkcKtJcvvctUc2wddxNmzzSZOcyAjOy/tdYooeqpoimkmlB +wh9K9SR8LRT1Pn0OhSEyeP6CEjS5r+4Xm2LHVd1GEqRdGUKFZKSfNpS7ma4/ -----END RSA PRIVATE KEY----- diff --git a/testkeys/ocsp/VeriSignCA.pem b/testkeys/ocsp/VeriSignCA.pem new file mode 100644 index 0000000..707ff08 --- /dev/null +++ b/testkeys/ocsp/VeriSignCA.pem @@ -0,0 +1,28 @@ +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- diff --git a/testkeys/ocsp/VeriSignIntermediate.pem b/testkeys/ocsp/VeriSignIntermediate.pem new file mode 100644 index 0000000..4e13f43 --- /dev/null +++ b/testkeys/ocsp/VeriSignIntermediate.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFODCCBCCgAwIBAgIQUT+5dDhwtzRAQY0wkwaZ/zANBgkqhkiG9w0BAQsFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMTMxMDMxMDAwMDAwWhcNMjMxMDMwMjM1OTU5WjB+MQsw +CQYDVQQGEwJVUzEdMBsGA1UEChMUU3ltYW50ZWMgQ29ycG9yYXRpb24xHzAdBgNV +BAsTFlN5bWFudGVjIFRydXN0IE5ldHdvcmsxLzAtBgNVBAMTJlN5bWFudGVjIENs +YXNzIDMgU2VjdXJlIFNlcnZlciBDQSAtIEc0MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAstgFyhx0LbUXVjnFSlIJluhL2AzxaJ+aQihiw6UwU35VEYJb +A3oNL+F5BMm0lncZgQGUWfm893qZJ4Itt4PdWid/sgN6nFMl6UgfRk/InSn4vnlW +9vf92Tpo2otLgjNBEsPIPMzWlnqEIRoiBAMnF4scaGGTDw5RgDMdtLXO637QYqzu +s3sBdO9pNevK1T2p7peYyo2qRA4lmUoVlqTObQJUHypqJuIGOmNIrLRM0XWTUP8T +L9ba4cYY9Z/JJV3zADreJk20KQnNDz0jbxZKgRb78oMQw7jW2FUyPfG9D72MUpVK +Fpd6UiFjdS8W+cRmvvW1Cdj/JwDNRHxvSz+w9wIDAQABo4IBYzCCAV8wEgYDVR0T +AQH/BAgwBgEB/wIBADAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vczEuc3ltY2Iu +Y29tL3BjYTMtZzUuY3JsMA4GA1UdDwEB/wQEAwIBBjAvBggrBgEFBQcBAQQjMCEw +HwYIKwYBBQUHMAGGE2h0dHA6Ly9zMi5zeW1jYi5jb20wawYDVR0gBGQwYjBgBgpg +hkgBhvhFAQc2MFIwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuc3ltYXV0aC5jb20v +Y3BzMCgGCCsGAQUFBwICMBwaGmh0dHA6Ly93d3cuc3ltYXV0aC5jb20vcnBhMCkG +A1UdEQQiMCCkHjAcMRowGAYDVQQDExFTeW1hbnRlY1BLSS0xLTUzNDAdBgNVHQ4E +FgQUX2DPYZBV34RDFIpgKrL1evRDGO8wHwYDVR0jBBgwFoAUf9Nlp8Ld7LvwMAnz +Qzn6Aq8zMTMwDQYJKoZIhvcNAQELBQADggEBAF6UVkndji1l9cE2UbYD49qecxny +H1mrWH5sJgUs+oHXXCMXIiw3k/eG7IXmsKP9H+IyqEVv4dn7ua/ScKAyQmW/hP4W +Ko8/xabWo5N9Q+l0IZE1KPRj6S7t9/Vcf0uatSDpCr3gRRAMFJSaXaXjS5HoJJtG +QGX0InLNmfiIEfXzf+YzguaoxX7+0AjiJVgIcWjmzaLmFN5OUiQt/eV5E1PnXi8t +TRttQBVSK/eHiXgSgW7ZTaoteNTCLD0IX4eRnh8OsN4wUmSGiaqdZpwOdgyA8nTY +Kvi4Os7X1g8RvmurFPW9QaAiY4nxug9vKWNmLT+sjHLF+8fk1A/yO0+MKcc= +-----END CERTIFICATE----- diff --git a/xcode/crypto.xcodeproj/project.pbxproj b/xcode/crypto.xcodeproj/project.pbxproj index f567ca1..f1d03c9 100644 --- a/xcode/crypto.xcodeproj/project.pbxproj +++ b/xcode/crypto.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ DD7AB35B1B979E3B0047DE55 /* asn1.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asn1.c; sourceTree = ""; }; DD7AB35C1B979E3B0047DE55 /* asn1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = asn1.h; sourceTree = ""; }; DD7AB3601B979E3B0047DE55 /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = ""; }; + 87EA02501CF4ED69001F4ECA /* crl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = crl.c; sourceTree = ""; }; DD7AB3621B979E3B0047DE55 /* pkcs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pkcs.c; sourceTree = ""; }; DD7AB3641B979E3B0047DE55 /* x509.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = x509.c; sourceTree = ""; }; DD7AB3651B979E3B0047DE55 /* x509.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = x509.h; sourceTree = ""; }; @@ -115,6 +116,7 @@ DD7AB35C1B979E3B0047DE55 /* asn1.h */, DD7AB35B1B979E3B0047DE55 /* asn1.c */, DD7AB3601B979E3B0047DE55 /* base64.c */, + 87EA02501CF4ED69001F4ECA /* crl.c */, DD7AB3621B979E3B0047DE55 /* pkcs.c */, DD7AB3651B979E3B0047DE55 /* x509.h */, DD7AB3641B979E3B0047DE55 /* x509.c */,