This commit is contained in:
kaleb-himes
2015-12-16 11:37:07 -07:00
19 changed files with 303 additions and 141 deletions

View File

@@ -50,11 +50,21 @@ wolfcrypt directories. Uncheck the following:
\#ifdef WOLFSSL\_VXWORKS block, a new GenerateSeed() function will need to be defined \#ifdef WOLFSSL\_VXWORKS block, a new GenerateSeed() function will need to be defined
in wolfcrypt/src/random.c. in wolfcrypt/src/random.c.
8. Include Entropy:
- Create a new project, similar to step 1 but choose VxWorks Source Build Project as the type of project instead of VxWorks Image Project.
- In the project directory, double click "Source Build Configuration" and under os > core > CORE\_KERNEL Menu > VxWorks Kernel Component Configuration find "Inject entropy in interrupts". Double click this.
- Go back to your VIP project. Right click the project and select "Properties".
- In "Properties", select "Project References". Check the box next to the new project you created. Click "Ok".
- Rebuild the project.
####3 Testing wolfSSL with VxWorks: ####3 Testing wolfSSL with VxWorks:
#####3.1 wolfCrypt Test and Benchmark Applications #####3.1 wolfCrypt Test and Benchmark Applications
The wolfCrypt test application will test each of the cryptographic algorithms The wolfCrypt test application will test each of the cryptographic algorithms
and output the status for each as a success or failure. The benchmark application will output the runtime of and output the status for each as a success or failure. The benchmark application will output the runtime of the cryptographic algorithms in milliseconds.
the cryptographic algorithms in milliseconds.
1. Include the following at the top of usrAppInit.c: 1. Include the following at the top of usrAppInit.c:

View File

@@ -61,15 +61,6 @@ EXTRA_DIST+= LICENSING
EXTRA_DIST+= INSTALL EXTRA_DIST+= INSTALL
EXTRA_DIST+= IPP EXTRA_DIST+= IPP
# user crypto plug in example
EXTRA_DIST+= wolfcrypt/user-crypto/configure.ac
EXTRA_DIST+= wolfcrypt/user-crypto/autogen.sh
EXTRA_DIST+= wolfcrypt/user-crypto/include/user_rsa.h
EXTRA_DIST+= wolfcrypt/user-crypto/src/rsa.c
EXTRA_DIST+= wolfcrypt/user-crypto/lib/.gitkeep
EXTRA_DIST+= wolfcrypt/user-crypto/README.txt
EXTRA_DIST+= wolfcrypt/user-crypto/Makefile.am
include wrapper/include.am include wrapper/include.am
include cyassl/include.am include cyassl/include.am
include wolfssl/include.am include wolfssl/include.am
@@ -81,6 +72,7 @@ include swig/include.am
include src/include.am include src/include.am
include support/include.am include support/include.am
include wolfcrypt/user-crypto/include.am
include wolfcrypt/benchmark/include.am include wolfcrypt/benchmark/include.am
include wolfcrypt/src/include.am include wolfcrypt/src/include.am
include wolfcrypt/test/include.am include wolfcrypt/test/include.am

View File

@@ -84,7 +84,7 @@ WOLFSSL_CALLBACKS needs LARGE_STATIC_BUFFERS, please add LARGE_STATIC_BUFFERS
#endif #endif
static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
const byte* input, int inSz, int type); const byte* input, int inSz, int type, int hashOutput);
#ifndef NO_WOLFSSL_CLIENT #ifndef NO_WOLFSSL_CLIENT
static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, word32*, static int DoHelloVerifyRequest(WOLFSSL* ssl, const byte* input, word32*,
@@ -967,14 +967,14 @@ void InitSuites(Suites* suites, ProtocolVersion pv, word16 haveRSA,
#endif #endif
#ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 #ifdef BUILD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
if (tls && haveRSA) { if (tls1_2 && haveRSA) {
suites->suites[idx++] = CHACHA_BYTE; suites->suites[idx++] = CHACHA_BYTE;
suites->suites[idx++] = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; suites->suites[idx++] = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
} }
#endif #endif
#ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 #ifdef BUILD_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
if (tls && haveRSA) { if (tls1_2 && haveRSA) {
suites->suites[idx++] = CHACHA_BYTE; suites->suites[idx++] = CHACHA_BYTE;
suites->suites[idx++] = TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256; suites->suites[idx++] = TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
} }
@@ -2282,6 +2282,7 @@ int DtlsPoolSave(WOLFSSL* ssl, const byte *src, int sz)
return MEMORY_ERROR; return MEMORY_ERROR;
} }
XMEMCPY(pBuf->buffer, src, sz); XMEMCPY(pBuf->buffer, src, sz);
pool->epoch[pool->used] = ssl->keys.dtls_epoch;
pBuf->length = (word32)sz; pBuf->length = (word32)sz;
pool->used++; pool->used++;
} }
@@ -2331,40 +2332,53 @@ int DtlsPoolTimeout(WOLFSSL* ssl)
int DtlsPoolSend(WOLFSSL* ssl) int DtlsPoolSend(WOLFSSL* ssl)
{ {
int ret; DtlsPool* pool = ssl->dtls_pool;
DtlsPool *pool = ssl->dtls_pool;
if (pool != NULL && pool->used > 0) { if (pool != NULL && pool->used > 0) {
int ret = 0;
int i; int i;
for (i = 0; i < pool->used; i++) { buffer* buf;
int sendResult;
buffer* buf = &pool->buf[i];
DtlsRecordLayerHeader* dtls = (DtlsRecordLayerHeader*)buf->buffer; for (i = 0, buf = pool->buf; i < pool->used; i++, buf++) {
if (pool->epoch[i] == 0) {
word16 message_epoch; DtlsRecordLayerHeader* dtls;
ato16(dtls->epoch, &message_epoch);
if (message_epoch == ssl->keys.dtls_epoch) {
/* Increment record sequence number on retransmitted handshake
* messages */
c32to48(ssl->keys.dtls_sequence_number, dtls->sequence_number);
ssl->keys.dtls_sequence_number++;
}
else {
/* The Finished message is sent with the next epoch, keep its
* sequence number */
}
dtls = (DtlsRecordLayerHeader*)buf->buffer;
c32to48(ssl->keys.dtls_prev_sequence_number++,
dtls->sequence_number);
if ((ret = CheckAvailableSize(ssl, buf->length)) != 0) if ((ret = CheckAvailableSize(ssl, buf->length)) != 0)
return ret; return ret;
XMEMCPY(ssl->buffers.outputBuffer.buffer, buf->buffer, buf->length); XMEMCPY(ssl->buffers.outputBuffer.buffer,
buf->buffer, buf->length);
ssl->buffers.outputBuffer.idx = 0; ssl->buffers.outputBuffer.idx = 0;
ssl->buffers.outputBuffer.length = buf->length; ssl->buffers.outputBuffer.length = buf->length;
}
else if (pool->epoch[i] == ssl->keys.dtls_epoch) {
byte* input;
byte* output;
int inputSz, sendSz;
sendResult = SendBuffered(ssl); input = buf->buffer;
if (sendResult < 0) { inputSz = buf->length;
return sendResult; sendSz = inputSz + MAX_MSG_EXTRA;
if ((ret = CheckAvailableSize(ssl, sendSz)) != 0)
return ret;
output = ssl->buffers.outputBuffer.buffer +
ssl->buffers.outputBuffer.length;
sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
handshake, 0);
if (sendSz < 0)
return BUILD_MSG_ERROR;
ssl->buffers.outputBuffer.length += sendSz;
}
ret = SendBuffered(ssl);
if (ret < 0) {
return ret;
} }
} }
} }
@@ -5091,14 +5105,6 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size,
if (!ssl->options.resuming) { if (!ssl->options.resuming) {
ssl->options.handShakeState = HANDSHAKE_DONE; ssl->options.handShakeState = HANDSHAKE_DONE;
ssl->options.handShakeDone = 1; ssl->options.handShakeDone = 1;
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
/* Other side has received our Finished, go to next epoch */
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 1;
}
#endif
} }
} }
else { else {
@@ -5106,14 +5112,6 @@ int DoFinished(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 size,
if (ssl->options.resuming) { if (ssl->options.resuming) {
ssl->options.handShakeState = HANDSHAKE_DONE; ssl->options.handShakeState = HANDSHAKE_DONE;
ssl->options.handShakeDone = 1; ssl->options.handShakeDone = 1;
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
/* Other side has received our Finished, go to next epoch */
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 1;
}
#endif
} }
} }
@@ -7464,7 +7462,7 @@ int SendChangeCipher(WOLFSSL* ssl)
input[0] = 1; /* turn it on */ input[0] = 1; /* turn it on */
sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
change_cipher_spec); change_cipher_spec, 0);
if (sendSz < 0) if (sendSz < 0)
return sendSz; return sendSz;
} }
@@ -7694,7 +7692,7 @@ static int BuildCertHashes(WOLFSSL* ssl, Hashes* hashes)
/* Build SSL Message, encrypted */ /* Build SSL Message, encrypted */
static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
const byte* input, int inSz, int type) const byte* input, int inSz, int type, int hashOutput)
{ {
#ifdef HAVE_TRUNCATED_HMAC #ifdef HAVE_TRUNCATED_HMAC
word32 digestSz = min(ssl->specs.hash_size, word32 digestSz = min(ssl->specs.hash_size,
@@ -7769,7 +7767,7 @@ static int BuildMessage(WOLFSSL* ssl, byte* output, int outSz,
XMEMCPY(output + idx, input, inSz); XMEMCPY(output + idx, input, inSz);
idx += inSz; idx += inSz;
if (type == handshake) { if (type == handshake && hashOutput) {
ret = HashOutput(ssl, output, headerSz + inSz, ivSz); ret = HashOutput(ssl, output, headerSz + inSz, ivSz);
if (ret != 0) if (ret != 0)
return ret; return ret;
@@ -7843,11 +7841,6 @@ int SendFinished(WOLFSSL* ssl)
int headerSz = HANDSHAKE_HEADER_SZ; int headerSz = HANDSHAKE_HEADER_SZ;
int outputSz; int outputSz;
#ifdef WOLFSSL_DTLS
word32 sequence_number = ssl->keys.dtls_sequence_number;
word16 epoch = ssl->keys.dtls_epoch;
#endif
/* setup encrypt keys */ /* setup encrypt keys */
if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0) if ((ret = SetKeysSide(ssl, ENCRYPT_SIDE_ONLY)) != 0)
return ret; return ret;
@@ -7859,11 +7852,11 @@ int SendFinished(WOLFSSL* ssl)
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
if (ssl->options.dtls) { if (ssl->options.dtls) {
/* Send Finished message with the next epoch, but don't commit that
* change until the other end confirms its reception. */
headerSz += DTLS_HANDSHAKE_EXTRA; headerSz += DTLS_HANDSHAKE_EXTRA;
ssl->keys.dtls_epoch++; ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 0; /* reset after epoch change */ ssl->keys.dtls_prev_sequence_number =
ssl->keys.dtls_sequence_number;
ssl->keys.dtls_sequence_number = 0;
} }
#endif #endif
@@ -7890,18 +7883,18 @@ int SendFinished(WOLFSSL* ssl)
} }
#endif #endif
sendSz = BuildMessage(ssl, output, outputSz, input, headerSz + finishedSz,
handshake);
if (sendSz < 0)
return BUILD_MSG_ERROR;
#ifdef WOLFSSL_DTLS #ifdef WOLFSSL_DTLS
if (ssl->options.dtls) { if (ssl->options.dtls) {
ssl->keys.dtls_epoch = epoch; if ((ret = DtlsPoolSave(ssl, input, headerSz + finishedSz)) != 0)
ssl->keys.dtls_sequence_number = sequence_number; return ret;
} }
#endif #endif
sendSz = BuildMessage(ssl, output, outputSz, input, headerSz + finishedSz,
handshake, 1);
if (sendSz < 0)
return BUILD_MSG_ERROR;
if (!ssl->options.resuming) { if (!ssl->options.resuming) {
#ifndef NO_SESSION_CACHE #ifndef NO_SESSION_CACHE
AddSession(ssl); /* just try */ AddSession(ssl); /* just try */
@@ -7909,36 +7902,14 @@ int SendFinished(WOLFSSL* ssl)
if (ssl->options.side == WOLFSSL_SERVER_END) { if (ssl->options.side == WOLFSSL_SERVER_END) {
ssl->options.handShakeState = HANDSHAKE_DONE; ssl->options.handShakeState = HANDSHAKE_DONE;
ssl->options.handShakeDone = 1; ssl->options.handShakeDone = 1;
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
/* Other side will soon receive our Finished, go to next
* epoch. */
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 1;
}
#endif
} }
} }
else { else {
if (ssl->options.side == WOLFSSL_CLIENT_END) { if (ssl->options.side == WOLFSSL_CLIENT_END) {
ssl->options.handShakeState = HANDSHAKE_DONE; ssl->options.handShakeState = HANDSHAKE_DONE;
ssl->options.handShakeDone = 1; ssl->options.handShakeDone = 1;
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
/* Other side will soon receive our Finished, go to next
* epoch. */
ssl->keys.dtls_epoch++;
ssl->keys.dtls_sequence_number = 1;
}
#endif
} }
} }
#ifdef WOLFSSL_DTLS
if (ssl->options.dtls) {
if ((ret = DtlsPoolSave(ssl, output, sendSz)) != 0)
return ret;
}
#endif
#ifdef WOLFSSL_CALLBACKS #ifdef WOLFSSL_CALLBACKS
if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo); if (ssl->hsInfoOn) AddPacketName("Finished", &ssl->handShakeInfo);
@@ -8146,7 +8117,7 @@ int SendCertificate(WOLFSSL* ssl)
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
} }
sendSz = BuildMessage(ssl, output, sendSz, input,inputSz,handshake); sendSz = BuildMessage(ssl, output,sendSz,input,inputSz,handshake,1);
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (sendSz < 0) if (sendSz < 0)
@@ -8361,7 +8332,7 @@ int SendData(WOLFSSL* ssl, const void* data, int sz)
} }
#endif #endif
sendSz = BuildMessage(ssl, out, outputSz, sendBuffer, buffSz, sendSz = BuildMessage(ssl, out, outputSz, sendBuffer, buffSz,
application_data); application_data, 0);
if (sendSz < 0) if (sendSz < 0)
return BUILD_MSG_ERROR; return BUILD_MSG_ERROR;
@@ -8512,7 +8483,7 @@ int SendAlert(WOLFSSL* ssl, int severity, int type)
/* only send encrypted alert if handshake actually complete, otherwise /* only send encrypted alert if handshake actually complete, otherwise
other side may not be able to handle it */ other side may not be able to handle it */
if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone) if (IsEncryptionOn(ssl, 1) && ssl->options.handShakeDone)
sendSz = BuildMessage(ssl, output, outputSz, input, ALERT_SIZE, alert); sendSz = BuildMessage(ssl, output, outputSz, input, ALERT_SIZE,alert,0);
else { else {
AddRecordHeader(output, ALERT_SIZE, alert, ssl); AddRecordHeader(output, ALERT_SIZE, alert, ssl);
@@ -10141,7 +10112,7 @@ static void PickHashSigAlgo(WOLFSSL* ssl,
return MEMORY_E; return MEMORY_E;
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
sendSz = BuildMessage(ssl, output, sendSz, input,inputSz,handshake); sendSz = BuildMessage(ssl, output,sendSz,input,inputSz,handshake,1);
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (sendSz < 0) if (sendSz < 0)
@@ -12313,7 +12284,7 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer)
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
sendSz = BuildMessage(ssl, output, sendSz, input, inputSz, sendSz = BuildMessage(ssl, output, sendSz, input, inputSz,
handshake); handshake, 1);
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (sendSz < 0) { if (sendSz < 0) {
#ifdef WOLFSSL_SMALL_STACK #ifdef WOLFSSL_SMALL_STACK
@@ -12686,7 +12657,7 @@ static word32 QSH_KeyExchangeWrite(WOLFSSL* ssl, byte isServer)
XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz); XMEMCPY(input, output + RECORD_HEADER_SZ, inputSz);
sendSz = BuildMessage(ssl, output, sendSz = BuildMessage(ssl, output,
MAX_CERT_VERIFY_SZ +MAX_MSG_EXTRA, MAX_CERT_VERIFY_SZ +MAX_MSG_EXTRA,
input, inputSz, handshake); input, inputSz, handshake, 1);
XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(input, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER);
if (sendSz < 0) if (sendSz < 0)

View File

@@ -16422,6 +16422,23 @@ void* wolfSSL_get_ex_data(const WOLFSSL* ssl, int idx)
#if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL) #if defined(HAVE_LIGHTY) || defined(HAVE_STUNNEL)
char * wolf_OBJ_nid2ln(int n) {
(void)n;
WOLFSSL_ENTER("wolf_OBJ_nid2ln");
WOLFSSL_STUB("wolf_OBJ_nid2ln");
return NULL;
}
int wolf_OBJ_txt2nid(const char* s) {
(void)s;
WOLFSSL_ENTER("wolf_OBJ_txt2nid");
WOLFSSL_STUB("wolf_OBJ_txt2nid");
return 0;
}
WOLFSSL_BIO *wolfSSL_BIO_new_file(const char *filename, const char *mode) { WOLFSSL_BIO *wolfSSL_BIO_new_file(const char *filename, const char *mode) {
(void)filename; (void)filename;
(void)mode; (void)mode;
@@ -16502,6 +16519,13 @@ long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX* ctx, WOLFSSL_DH* dh)
/* stunnel compatability functions*/ /* stunnel compatability functions*/
#if defined(OPENSSL_EXTRA) && defined(HAVE_STUNNEL) #if defined(OPENSSL_EXTRA) && defined(HAVE_STUNNEL)
void WOLFSSL_ERR_remove_thread_state(void* pid)
{
(void) pid;
return;
}
int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data) int wolfSSL_SESSION_set_ex_data(WOLFSSL_SESSION* session, int idx, void* data)
{ {
WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data"); WOLFSSL_ENTER("wolfSSL_SESSION_set_ex_data");
@@ -16567,6 +16591,19 @@ WOLFSSL_DH *wolfSSL_DH_generate_parameters(int prime_len, int generator,
return NULL; return NULL;
} }
int wolfSSL_DH_generate_parameters_ex(WOLFSSL_DH* dh, int prime_len, int generator,
void (*callback) (int, int, void *))
{
(void)prime_len;
(void)generator;
(void)callback;
(void)dh;
WOLFSSL_ENTER("wolfSSL_DH_generate_parameters_ex");
WOLFSSL_STUB("wolfSSL_DH_generate_parameters_ex");
return -1;
}
void wolfSSL_ERR_load_crypto_strings(void) void wolfSSL_ERR_load_crypto_strings(void)
{ {
@@ -16865,6 +16902,52 @@ void wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX* ctx, void* arg)
if (ctx) if (ctx)
ctx->sniRecvCbArg = arg; ctx->sniRecvCbArg = arg;
} }
long wolfSSL_CTX_clear_options(WOLFSSL_CTX* ctx, long opt)
{
WOLFSSL_ENTER("SSL_CTX_clear_options");
WOLFSSL_STUB("SSL_CTX_clear_options");
(void)ctx;
(void)opt;
return opt;
}
void wolfSSL_THREADID_set_callback(void(*threadid_func)(void*))
{
WOLFSSL_ENTER("wolfSSL_THREADID_set_callback");
WOLFSSL_STUB("wolfSSL_THREADID_set_callback");
(void)threadid_func;
return;
}
void wolfSSL_THREADID_set_numeric(void* id, unsigned long val)
{
WOLFSSL_ENTER("wolfSSL_THREADID_set_numeric");
WOLFSSL_STUB("wolfSSL_THREADID_set_numeric");
(void)id;
(void)val;
return;
}
WOLFSSL_X509* wolfSSL_X509_STORE_get1_certs(WOLFSSL_X509_STORE_CTX* ctx,
WOLFSSL_X509_NAME* name)
{
WOLFSSL_ENTER("wolfSSL_X509_STORE_get1_certs");
WOLFSSL_STUB("wolfSSL_X509_STORE_get1_certs");
(void)ctx;
(void)name;
return NULL;
}
void wolfSSL_sk_X509_pop_free(STACK_OF(WOLFSSL_X509)* sk, void f (WOLFSSL_X509*)){
(void) sk;
(void) f;
WOLFSSL_ENTER("wolfSSL_sk_X509_pop_free");
WOLFSSL_STUB("wolfSSL_sk_X509_pop_free");
}
#endif /* OPENSSL_EXTRA and HAVE_STUNNEL */ #endif /* OPENSSL_EXTRA and HAVE_STUNNEL */
#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519) #if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519)

View File

@@ -2166,7 +2166,7 @@ int wc_AesSetIV(Aes* aes, const byte* iv)
{ {
XMEMCPY(temp_block, in + offset, AES_BLOCK_SIZE); XMEMCPY(temp_block, in + offset, AES_BLOCK_SIZE);
wc_AesEncrypt(aes, in + offset, out + offset); wc_AesDecrypt(aes, in + offset, out + offset);
/* XOR block with IV for CBC */ /* XOR block with IV for CBC */
for (i = 0; i < AES_BLOCK_SIZE; i++) for (i = 0; i < AES_BLOCK_SIZE; i++)

View File

@@ -1980,11 +1980,7 @@ int wc_DsaKeyToDer(DsaKey* key, byte* output, word32 inLen)
mp_int* keyInt = GetDsaInt(key, i); mp_int* keyInt = GetDsaInt(key, i);
/* leading zero */ /* leading zero */
if ((mp_count_bits(keyInt) & 7) == 0 || mp_iszero(keyInt) == MP_YES) lbit = mp_leading_bit(keyInt);
lbit = 1;
else
lbit = 0;
rawLen = mp_unsigned_bin_size(keyInt) + lbit; rawLen = mp_unsigned_bin_size(keyInt) + lbit;
tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, NULL, DYNAMIC_TYPE_DSA); tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, NULL, DYNAMIC_TYPE_DSA);
@@ -5606,11 +5602,7 @@ int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
mp_int* keyInt = GetRsaInt(key, i); mp_int* keyInt = GetRsaInt(key, i);
/* leading zero */ /* leading zero */
if ((mp_count_bits(keyInt) & 7) == 0 || mp_iszero(keyInt) == MP_YES) lbit = mp_leading_bit(keyInt);
lbit = 1;
else
lbit = 0;
rawLen = mp_unsigned_bin_size(keyInt) + lbit; rawLen = mp_unsigned_bin_size(keyInt) + lbit;
tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap, tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap,

View File

@@ -1285,6 +1285,23 @@ int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
return 0; return 0;
} }
#elif defined(WOLFSSL_VXWORKS)
#include <randomNumGen.h>
int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz) {
STATUS status;
/* RANDOM ENTORPY INJECT component must be enabled in VSB project */
status = randBytes (output, sz);
if (status == ERROR) {
WOLFSSL_MSG("Random seed failed! Enable RANDOM ENTROPY INJECT.");
return RNG_FAILURE_E;
}
return 0;
}
#elif defined(CUSTOM_RAND_GENERATE) #elif defined(CUSTOM_RAND_GENERATE)
/* Implement your own random generation function /* Implement your own random generation function

View File

@@ -175,7 +175,7 @@ int wc_SignatureGenerate(
enum wc_HashType hash_type, enum wc_SignatureType sig_type, enum wc_HashType hash_type, enum wc_SignatureType sig_type,
const byte* data, word32 data_len, const byte* data, word32 data_len,
byte* sig, word32 *sig_len, byte* sig, word32 *sig_len,
const void* key, word32 key_len, RNG* rng) const void* key, word32 key_len, WC_RNG* rng)
{ {
int ret, hash_len; int ret, hash_len;
byte *hash_data = NULL; byte *hash_data = NULL;

View File

@@ -0,0 +1,13 @@
if BUILD_FAST_RSA
include_HEADERS += wolfcrypt/user-crypto/include/user_rsa.h
endif
# user crypto plug in example
EXTRA_DIST+= wolfcrypt/user-crypto/configure.ac
EXTRA_DIST+= wolfcrypt/user-crypto/autogen.sh
EXTRA_DIST+= wolfcrypt/user-crypto/include/user_rsa.h
EXTRA_DIST+= wolfcrypt/user-crypto/src/rsa.c
EXTRA_DIST+= wolfcrypt/user-crypto/lib/.gitkeep
EXTRA_DIST+= wolfcrypt/user-crypto/README.txt
EXTRA_DIST+= wolfcrypt/user-crypto/Makefile.am

View File

@@ -106,7 +106,7 @@ WOLFSSL_API int wc_RsaFlattenPublicKey(RsaKey*, byte*, word32*, byte*,
word32*); word32*);
#ifdef WOLFSSL_CERT_GEN #if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN)
/* abstracted BN operations with RSA key */ /* abstracted BN operations with RSA key */
WOLFSSL_API int wc_Rsa_leading_bit(void* BN); WOLFSSL_API int wc_Rsa_leading_bit(void* BN);
WOLFSSL_API int wc_Rsa_unsigned_bin_size(void* BN); WOLFSSL_API int wc_Rsa_unsigned_bin_size(void* BN);

View File

@@ -91,22 +91,56 @@ int wc_InitRsaKey(RsaKey* key, void* heap)
} }
#ifdef WOLFSSL_CERT_GEN /* three functions needed for cert gen */ /* three functions needed for cert and key gen */
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN)
/* return 1 if there is a leading bit*/ /* return 1 if there is a leading bit*/
int wc_Rsa_leading_bit(void* bn) int wc_Rsa_leading_bit(void* bn)
{ {
int ret = 0; int ret = 0;
if (ippsExtGet_BN(NULL, &ret, NULL, bn) != ippStsNoErr) { int dataSz;
USER_DEBUG(("Rsa leading bit error\n")); Ipp32u* data;
Ipp32u q;
int qSz = sizeof(Ipp32u);
if (ippsExtGet_BN(NULL, &dataSz, NULL, bn) != ippStsNoErr) {
USER_DEBUG(("ippsExtGet_BN Rsa leading bit error\n"));
return USER_CRYPTO_ERROR; return USER_CRYPTO_ERROR;
} }
return (ret % 8)? 1 : 0; /* if mod 8 bit then an extra byte is needed */
/* convert from size in binary to Ipp32u */
dataSz = dataSz / 32 + ((dataSz % 32)? 1 : 0);
data = (Ipp32u*)XMALLOC(dataSz * sizeof(Ipp32u), NULL,
DYNAMIC_TYPE_USER_CRYPTO);
if (data == NULL) {
USER_DEBUG(("Rsa leading bit memory error\n"));
return 0;
}
/* extract value from BN */
if (ippsExtGet_BN(NULL, NULL, data, bn) != ippStsNoErr) {
USER_DEBUG(("Rsa leading bit error\n"));
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return 0;
}
/* use method like what's used in wolfssl tfm.c */
q = data[dataSz - 1];
ret = 0;
while (qSz > 0) {
if (q != 0)
ret = (q & 0x80) != 0;
q >>= 8;
qSz--;
}
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
return ret;
} }
/* get the size in bytes of BN /* get the size in bytes of BN */
cuts off if extra byte is needed so recommended to check wc_Rsa_leading_bit
and adding it to this return value before mallocing memory needed */
int wc_Rsa_unsigned_bin_size(void* bn) int wc_Rsa_unsigned_bin_size(void* bn)
{ {
int ret = 0; int ret = 0;
@@ -114,7 +148,7 @@ int wc_Rsa_unsigned_bin_size(void* bn)
USER_DEBUG(("Rsa unsigned bin size error\n")); USER_DEBUG(("Rsa unsigned bin size error\n"));
return USER_CRYPTO_ERROR; return USER_CRYPTO_ERROR;
} }
return ret / 8; /* size in bytes */ return (ret / 8) + ((ret % 8)? 1: 0); /* size in bytes */
} }
#ifndef MP_OKAY #ifndef MP_OKAY
@@ -125,12 +159,12 @@ int wc_Rsa_unsigned_bin_size(void* bn)
int wc_Rsa_to_unsigned_bin(void* bn, byte* in, int inLen) int wc_Rsa_to_unsigned_bin(void* bn, byte* in, int inLen)
{ {
if (ippsGetOctString_BN((Ipp8u*)in, inLen, bn) != ippStsNoErr) { if (ippsGetOctString_BN((Ipp8u*)in, inLen, bn) != ippStsNoErr) {
USER_DEBUG(("Rsa unsigned bin error\n")); USER_DEBUG(("Rsa to unsigned bin error\n"));
return USER_CRYPTO_ERROR; return USER_CRYPTO_ERROR;
} }
return MP_OKAY; return MP_OKAY;
} }
#endif /* WOLFSSL_CERT_GEN */ #endif /* WOLFSSL_CERT_GEN or WOLFSSL_KEY_GEN */
#ifdef OPENSSL_EXTRA /* functions needed for openssl compatibility layer */ #ifdef OPENSSL_EXTRA /* functions needed for openssl compatibility layer */
@@ -1936,6 +1970,7 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
IppsBigNumState* pSrcPublicExp; IppsBigNumState* pSrcPublicExp;
Ipp8u* scratchBuffer; Ipp8u* scratchBuffer;
Ipp8u eAry[8];
int trys = 8; /* Miller-Rabin test parameter */ int trys = 8; /* Miller-Rabin test parameter */
IppsPrimeState* pPrime; IppsPrimeState* pPrime;
@@ -2015,11 +2050,16 @@ int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
/* set up initial value of pScrPublicExp */ /* set up initial value of pScrPublicExp */
leng = (int)sizeof(long); /* # of Ipp32u in long */ leng = (int)sizeof(long); /* # of Ipp32u in long */
/* place the value of e into the array eAry then load into BN */
for (i = 0; i < leng; i++) {
eAry[i] = (e >> (8 * (leng - 1 - i))) & 0XFF;
}
ret = init_bn(&pSrcPublicExp, leng); ret = init_bn(&pSrcPublicExp, leng);
if (ret != ippStsNoErr) if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR; return USER_CRYPTO_ERROR;
ret = ippsSetOctString_BN((Ipp8u*)&e, leng, pSrcPublicExp); ret = ippsSetOctString_BN(eAry, leng, pSrcPublicExp);
if (ret != ippStsNoErr) if (ret != ippStsNoErr)
return USER_CRYPTO_ERROR; return USER_CRYPTO_ERROR;
@@ -2300,10 +2340,12 @@ static int SetRsaPublicKey(byte* output, RsaKey* key,
return USER_CRYPTO_ERROR; return USER_CRYPTO_ERROR;
#endif #endif
if (ippsExtGet_BN(NULL, &rawLen, NULL, key->n) != ippStsNoErr) leadingBit = wc_Rsa_leading_bit(key->n);
rawLen = wc_Rsa_unsigned_bin_size(key->n);
if ((int)rawLen < 0) {
return USER_CRYPTO_ERROR; return USER_CRYPTO_ERROR;
leadingBit = rawLen % 8; /* check for if an extra byte is needed */ }
rawLen = rawLen/8; /* convert to byte size */
rawLen = rawLen + leadingBit; rawLen = rawLen + leadingBit;
n[0] = ASN_INTEGER; n[0] = ASN_INTEGER;
nSz = SetLength(rawLen, n + 1) + 1; /* int tag */ nSz = SetLength(rawLen, n + 1) + 1; /* int tag */
@@ -2339,10 +2381,12 @@ static int SetRsaPublicKey(byte* output, RsaKey* key,
} }
#endif #endif
if (ippsExtGet_BN(NULL, &rawLen, NULL, key->e) != ippStsNoErr) leadingBit = wc_Rsa_leading_bit(key->e);
rawLen = wc_Rsa_unsigned_bin_size(key->e);
if ((int)rawLen < 0) {
return USER_CRYPTO_ERROR; return USER_CRYPTO_ERROR;
leadingBit = rawLen % 8; }
rawLen = rawLen/8;
rawLen = rawLen + leadingBit; rawLen = rawLen + leadingBit;
e[0] = ASN_INTEGER; e[0] = ASN_INTEGER;
eSz = SetLength(rawLen, e + 1) + 1; /* int tag */ eSz = SetLength(rawLen, e + 1) + 1; /* int tag */
@@ -2510,15 +2554,18 @@ int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
Ipp32u isZero; Ipp32u isZero;
IppsBigNumState* keyInt = GetRsaInt(key, i); IppsBigNumState* keyInt = GetRsaInt(key, i);
/* leading zero */
ippsCmpZero_BN(keyInt, &isZero); /* makes isZero 0 if true */ ippsCmpZero_BN(keyInt, &isZero); /* makes isZero 0 if true */
ippsExtGet_BN(NULL, (int*)&rawLen, NULL, keyInt); /* bit length */ rawLen = wc_Rsa_unsigned_bin_size(keyInt);
if (rawLen % 8 || !isZero) if ((int)rawLen < 0) {
return USER_CRYPTO_ERROR;
}
/* leading zero */
if (!isZero || wc_Rsa_leading_bit(keyInt))
lbit = 1; lbit = 1;
else else
lbit = 0; lbit = 0;
rawLen /= 8; /* convert to bytes */
rawLen += lbit; rawLen += lbit;
tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap, tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap,
@@ -2548,6 +2595,8 @@ int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
} }
else { else {
ret = USER_CRYPTO_ERROR; ret = USER_CRYPTO_ERROR;
USER_DEBUG(("ippsGetOctString_BN error %s\n",
ippGetStatusString(err)));
break; break;
} }
} }

View File

@@ -1445,8 +1445,9 @@ typedef struct Keys {
word16 dtls_peer_handshake_number; word16 dtls_peer_handshake_number;
word16 dtls_expected_peer_handshake_number; word16 dtls_expected_peer_handshake_number;
word16 dtls_epoch; /* Current tx epoch */
word32 dtls_sequence_number; /* Current tx sequence */ word32 dtls_sequence_number; /* Current tx sequence */
word32 dtls_prev_sequence_number; /* Previous epoch's seq number*/
word16 dtls_epoch; /* Current tx epoch */
word16 dtls_handshake_number; /* Current tx handshake seq */ word16 dtls_handshake_number; /* Current tx handshake seq */
#endif #endif
@@ -2289,6 +2290,7 @@ typedef struct DtlsRecordLayerHeader {
typedef struct DtlsPool { typedef struct DtlsPool {
buffer buf[DTLS_POOL_SZ]; buffer buf[DTLS_POOL_SZ];
word16 epoch[DTLS_POOL_SZ];
int used; int used;
} DtlsPool; } DtlsPool;

View File

@@ -14,6 +14,8 @@
WOLFSSL_API const char* wolfSSLeay_version(int type); WOLFSSL_API const char* wolfSSLeay_version(int type);
WOLFSSL_API unsigned long wolfSSLeay(void); WOLFSSL_API unsigned long wolfSSLeay(void);
#define CRYPTO_THREADID void
#define SSLeay_version wolfSSLeay_version #define SSLeay_version wolfSSLeay_version
#define SSLeay wolfSSLeay #define SSLeay wolfSSLeay
@@ -28,6 +30,8 @@ WOLFSSL_API unsigned long wolfSSLeay(void);
typedef struct CRYPTO_EX_DATA CRYPTO_EX_DATA; typedef struct CRYPTO_EX_DATA CRYPTO_EX_DATA;
typedef void (CRYPTO_free_func)(void*parent, void*ptr, CRYPTO_EX_DATA *ad, int idx, typedef void (CRYPTO_free_func)(void*parent, void*ptr, CRYPTO_EX_DATA *ad, int idx,
long argl, void* argp); long argl, void* argp);
#define CRYPTO_THREADID_set_callback wolfSSL_THREADID_set_callback
#define CRYPTO_THREADID_set_numeric wolfSSL_THREADID_set_numeric
#endif /* HAVE_STUNNEL */ #endif /* HAVE_STUNNEL */
#endif /* header */ #endif /* header */

View File

@@ -50,5 +50,6 @@ typedef WOLFSSL_DH DH;
#ifdef HAVE_STUNNEL #ifdef HAVE_STUNNEL
#define DH_generate_parameters wolfSSL_DH_generate_parameters #define DH_generate_parameters wolfSSL_DH_generate_parameters
#define DH_generate_parameters_ex wolfSSL_DH_generate_parameters_ex
#endif /* HAVE_STUNNEL */ #endif /* HAVE_STUNNEL */
#endif /* header */ #endif /* header */

View File

@@ -8,7 +8,7 @@
#if defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY) #if defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY)
/* version number can be increased for Lighty after compatibility for ECDH /* version number can be increased for Lighty after compatibility for ECDH
is added */ is added */
#define OPENSSL_VERSION_NUMBER 0x0090700fL #define OPENSSL_VERSION_NUMBER 0x10001000L
#else #else
#define OPENSSL_VERSION_NUMBER 0x0090810fL #define OPENSSL_VERSION_NUMBER 0x0090810fL
#endif #endif

View File

@@ -431,6 +431,8 @@ typedef WOLFSSL_X509_NAME_ENTRY X509_NAME_ENTRY;
#if defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY) #if defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY)
#define OBJ_nid2ln wolf_OBJ_nid2ln
#define OBJ_txt2nid wolf_OBJ_txt2nid
#define PEM_read_bio_DHparams wolfSSL_PEM_read_bio_DHparams #define PEM_read_bio_DHparams wolfSSL_PEM_read_bio_DHparams
#define PEM_write_bio_X509 PEM_write_bio_WOLFSSL_X509 #define PEM_write_bio_X509 PEM_write_bio_WOLFSSL_X509
#define SSL_CTX_set_tmp_dh wolfSSL_CTX_set_tmp_dh #define SSL_CTX_set_tmp_dh wolfSSL_CTX_set_tmp_dh
@@ -477,6 +479,8 @@ typedef WOLFSSL_X509_NAME_ENTRY X509_NAME_ENTRY;
#define SSL_SESSION_get_id wolfSSL_SESSION_get_id #define SSL_SESSION_get_id wolfSSL_SESSION_get_id
#define CRYPTO_dynlock_value WOLFSSL_dynlock_value #define CRYPTO_dynlock_value WOLFSSL_dynlock_value
typedef WOLFSSL_ASN1_BIT_STRING ASN1_BIT_STRING; typedef WOLFSSL_ASN1_BIT_STRING ASN1_BIT_STRING;
#define X509_STORE_get1_certs wolfSSL_X509_STORE_get1_certs
#define sk_X509_pop_free wolfSSL_sk_X509_pop_free
#define SSL_TLSEXT_ERR_OK 0 #define SSL_TLSEXT_ERR_OK 0
#define SSL_TLSEXT_ERR_ALERT_FATAL alert_fatal #define SSL_TLSEXT_ERR_ALERT_FATAL alert_fatal
@@ -492,6 +496,8 @@ typedef WOLFSSL_ASN1_BIT_STRING ASN1_BIT_STRING;
#define PSK_MAX_PSK_LEN 256 #define PSK_MAX_PSK_LEN 256
#define PSK_MAX_IDENTITY_LEN 128 #define PSK_MAX_IDENTITY_LEN 128
#define ERR_remove_thread_state WOLFSSL_ERR_remove_thread_state
#define SSL_CTX_clear_options wolfSSL_CTX_clear_options
#endif /* HAVE_STUNNEL */ #endif /* HAVE_STUNNEL */

View File

@@ -1620,6 +1620,8 @@ WOLFSSL_API STACK_OF(WOLFSSL_X509_NAME) *wolfSSL_dup_CA_list( STACK_OF(WOLFSSL_X
#if defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY) #if defined(HAVE_STUNNEL) || defined(HAVE_LIGHTY)
WOLFSSL_API char * wolf_OBJ_nid2ln(int n);
WOLFSSL_API int wolf_OBJ_txt2nid(const char *sn);
WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_new_file(const char *filename, const char *mode); WOLFSSL_API WOLFSSL_BIO* wolfSSL_BIO_new_file(const char *filename, const char *mode);
WOLFSSL_API long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX*, WOLFSSL_DH*); WOLFSSL_API long wolfSSL_CTX_set_tmp_dh(WOLFSSL_CTX*, WOLFSSL_DH*);
WOLFSSL_API WOLFSSL_DH *wolfSSL_PEM_read_bio_DHparams(WOLFSSL_BIO *bp, WOLFSSL_API WOLFSSL_DH *wolfSSL_PEM_read_bio_DHparams(WOLFSSL_BIO *bp,
@@ -1643,6 +1645,9 @@ WOLFSSL_API int wolfSSL_CRYPTO_set_mem_ex_functions(void *(*m) (size_t, const ch
WOLFSSL_API WOLFSSL_DH *wolfSSL_DH_generate_parameters(int prime_len, int generator, WOLFSSL_API WOLFSSL_DH *wolfSSL_DH_generate_parameters(int prime_len, int generator,
void (*callback) (int, int, void *), void *cb_arg); void (*callback) (int, int, void *), void *cb_arg);
WOLFSSL_API int wolfSSL_DH_generate_parameters_ex(WOLFSSL_DH*, int, int,
void (*callback) (int, int, void *));
WOLFSSL_API void wolfSSL_ERR_load_crypto_strings(void); WOLFSSL_API void wolfSSL_ERR_load_crypto_strings(void);
WOLFSSL_API unsigned long wolfSSL_ERR_peek_last_error(void); WOLFSSL_API unsigned long wolfSSL_ERR_peek_last_error(void);
@@ -1708,6 +1713,19 @@ WOLFSSL_API void wolfSSL_CTX_set_servername_callback(WOLFSSL_CTX *,
CallbackSniRecv); CallbackSniRecv);
WOLFSSL_API void wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX *, void*); WOLFSSL_API void wolfSSL_CTX_set_servername_arg(WOLFSSL_CTX *, void*);
WOLFSSL_API void WOLFSSL_ERR_remove_thread_state(void*);
WOLFSSL_API long wolfSSL_CTX_clear_options(WOLFSSL_CTX*, long);
WOLFSSL_API void wolfSSL_THREADID_set_callback(void (*threadid_func)(void*));
WOLFSSL_API void wolfSSL_THREADID_set_numeric(void* id, unsigned long val);
WOLFSSL_API WOLFSSL_X509* wolfSSL_X509_STORE_get1_certs(WOLFSSL_X509_STORE_CTX*,
WOLFSSL_X509_NAME*);
WOLFSSL_API void wolfSSL_sk_X509_pop_free(STACK_OF(WOLFSSL_X509)* sk, void f (WOLFSSL_X509*));
#endif /* HAVE_STUNNEL */ #endif /* HAVE_STUNNEL */
#ifdef WOLFSSL_JNI #ifdef WOLFSSL_JNI

View File

@@ -85,6 +85,10 @@ typedef struct {
* Do not enable ALT_ECC_SIZE and disable fast math in the configuration. * Do not enable ALT_ECC_SIZE and disable fast math in the configuration.
*/ */
#ifndef USE_FAST_MATH
#error USE_FAST_MATH must be defined to use ALT_ECC_SIZE
#endif
#ifndef FP_MAX_BITS_ECC #ifndef FP_MAX_BITS_ECC
#define FP_MAX_BITS_ECC 528 #define FP_MAX_BITS_ECC 528
#endif #endif

View File

@@ -54,7 +54,7 @@ WOLFSSL_API int wc_SignatureGenerate(
const byte* data, word32 data_len, const byte* data, word32 data_len,
byte* sig, word32 *sig_len, byte* sig, word32 *sig_len,
const void* key, word32 key_len, const void* key, word32 key_len,
RNG* rng); WC_RNG* rng);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */