/** @fn int soap_smd_update(struct soap *soap, struct soap_smd_data *data, const char *buf, size_t len) @brief Updates (signed) digest computation with message part. @param soap context @param[in,out] data smdevp engine context @param[in] buf contains message part @param[in] len of message part @return SOAP_OK or SOAP_SSL_ERROR */ int soap_smd_update(struct soap *soap, struct soap_smd_data *data, const char *buf, size_t len) { int err = 1; DBGLOG(TEST, SOAP_MESSAGE(fdebug, "-- SMD Update alg=%d n=%lu (%p) --\n", data->alg, (unsigned long)len, data->ctx)); switch (data->alg & (SOAP_SMD_PASSTHRU-1)) { case SOAP_SMD_DGST_MD5: case SOAP_SMD_DGST_SHA1: EVP_DigestUpdate((EVP_MD_CTX*)data->ctx, (const void*)buf, (unsigned int)len); break; case SOAP_SMD_HMAC_SHA1: HMAC_Update((HMAC_CTX*)data->ctx, (const unsigned char*)buf, len); break; case SOAP_SMD_SIGN_DSA_SHA1: case SOAP_SMD_SIGN_RSA_SHA1: err = EVP_SignUpdate((EVP_MD_CTX*)data->ctx, (const void*)buf, (unsigned int)len); break; case SOAP_SMD_VRFY_DSA_SHA1: case SOAP_SMD_VRFY_RSA_SHA1: err = EVP_VerifyUpdate((EVP_MD_CTX*)data->ctx, (const void*)buf, (unsigned int)len); break; } DBGMSG(TEST, buf, len); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--")); /* check and return */ return soap_smd_check(soap, data, err, "soap_smd_update() failed"); }
/** @fn int soap_smd_update(struct soap *soap, struct soap_smd_data *data, const char *buf, size_t len) @brief Updates (signed) digest computation with message part. @param soap context @param[in,out] data smdevp engine context @param[in] buf contains message part @param[in] len of message part @return SOAP_OK or SOAP_SSL_ERROR */ int soap_smd_update(struct soap *soap, struct soap_smd_data *data, const char *buf, size_t len) { int ok = 1; if (!data->ctx) return soap_set_receiver_error(soap, "soap_smd_update() failed", "No context", SOAP_SSL_ERROR); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "-- SMD Update alg=%x n=%lu (%p) --\n", data->alg, (unsigned long)len, data->ctx)); switch (data->alg & SOAP_SMD_ALGO) { case SOAP_SMD_HMAC: HMAC_Update((HMAC_CTX*)data->ctx, (const unsigned char*)buf, len); break; case SOAP_SMD_DGST: EVP_DigestUpdate((EVP_MD_CTX*)data->ctx, (const void*)buf, (unsigned int)len); break; case SOAP_SMD_SIGN: ok = EVP_SignUpdate((EVP_MD_CTX*)data->ctx, (const void*)buf, (unsigned int)len); break; case SOAP_SMD_VRFY: ok = EVP_VerifyUpdate((EVP_MD_CTX*)data->ctx, (const void*)buf, (unsigned int)len); break; } DBGMSG(TEST, buf, len); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--")); /* check and return */ return soap_smd_check(soap, data, ok, "soap_smd_update() failed"); }
/** @fn int soap_smd_init(struct soap *soap, struct soap_smd_data *data, int alg, const void *key, int keylen) @brief Initiates a (signed) digest computation. @param soap context @param[in,out] data smdevp engine context @param[in] alg is algorithm to use @param[in] key is key to use or NULL for digests @param[in] keylen is length of HMAC key (when provided) @return SOAP_OK or SOAP_SSL_ERROR */ int soap_smd_init(struct soap *soap, struct soap_smd_data *data, int alg, const void *key, int keylen) { static int done = 0; int err = 1; #ifdef WITH_OPENSSL /* OpenSSL: make sure we have the digest algorithms, need to call just once */ if (!done) { done = 1; OpenSSL_add_all_digests(); OpenSSL_add_all_algorithms(); } #endif /* the algorithm to use */ data->alg = alg; /* the key to use */ data->key = key; /* allocate and init the OpenSSL HMAC or EVP_MD context */ if ((alg & (SOAP_SMD_PASSTHRU-1)) == SOAP_SMD_HMAC_SHA1) { data->ctx = (void*)SOAP_MALLOC(soap, sizeof(HMAC_CTX)); HMAC_CTX_init((HMAC_CTX*)data->ctx); } else { data->ctx = (void*)SOAP_MALLOC(soap, sizeof(EVP_MD_CTX)); EVP_MD_CTX_init((EVP_MD_CTX*)data->ctx); } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "-- SMD Init alg=%d (%p) --\n", alg, data->ctx)); /* init the digest or signature computations */ switch (alg & (SOAP_SMD_PASSTHRU-1)) { case SOAP_SMD_DGST_MD5: EVP_DigestInit((EVP_MD_CTX*)data->ctx, EVP_md5()); break; case SOAP_SMD_DGST_SHA1: EVP_DigestInit((EVP_MD_CTX*)data->ctx, EVP_sha1()); break; case SOAP_SMD_DGST_SHA256: EVP_DigestInit((EVP_MD_CTX*)data->ctx, EVP_sha256()); break; case SOAP_SMD_HMAC_SHA1: HMAC_Init((HMAC_CTX*)data->ctx, key, keylen, EVP_sha1()); break; case SOAP_SMD_SIGN_DSA_SHA1: err = EVP_SignInit((EVP_MD_CTX*)data->ctx, EVP_dss1()); break; case SOAP_SMD_SIGN_RSA_SHA1: err = EVP_SignInit((EVP_MD_CTX*)data->ctx, EVP_sha1()); break; case SOAP_SMD_SIGN_RSA_SHA256: err = EVP_SignInit((EVP_MD_CTX*)data->ctx, EVP_sha256()); break; case SOAP_SMD_VRFY_DSA_SHA1: err = EVP_VerifyInit((EVP_MD_CTX*)data->ctx, EVP_dss1()); break; case SOAP_SMD_VRFY_RSA_SHA1: err = EVP_VerifyInit((EVP_MD_CTX*)data->ctx, EVP_sha1()); break; } /* check and return */ return soap_smd_check(soap, data, err, "soap_smd_init() failed"); }
/** @fn int soap_smd_final(struct soap *soap, struct soap_smd_data *data, char *buf, int *len) @brief Finalizes (signed) digest computation and returns digest or signature. @param soap context @param[in,out] data smdevp engine context @param[in] buf contains signature for verification (SOAP_SMD_VRFY algorithms) @param[out] buf is populated with the digest or signature @param[in] len points to length of signature to verify (SOAP_SMD_VRFY algorithms) @param[out] len points to length of stored digest or signature (pass NULL if you are not interested in this value) @return SOAP_OK or SOAP_SSL_ERROR */ int soap_smd_final(struct soap *soap, struct soap_smd_data *data, char *buf, int *len) { unsigned int n = 0; int err = 1; if (buf) { /* finalize the digest or signature computation */ switch (data->alg & (SOAP_SMD_PASSTHRU-1)) { case SOAP_SMD_DGST_MD5: case SOAP_SMD_DGST_SHA1: case SOAP_SMD_DGST_SHA256: EVP_DigestFinal((EVP_MD_CTX*)data->ctx, (unsigned char*)buf, &n); break; case SOAP_SMD_HMAC_SHA1: HMAC_Final((HMAC_CTX*)data->ctx, (unsigned char*)buf, &n); break; case SOAP_SMD_SIGN_DSA_SHA1: case SOAP_SMD_SIGN_RSA_SHA1: case SOAP_SMD_SIGN_RSA_SHA256: err = EVP_SignFinal((EVP_MD_CTX*)data->ctx, (unsigned char*)buf, &n, (EVP_PKEY*)data->key); break; case SOAP_SMD_VRFY_DSA_SHA1: case SOAP_SMD_VRFY_RSA_SHA1: if (len) { n = (unsigned int)*len; err = EVP_VerifyFinal((EVP_MD_CTX*)data->ctx, (unsigned char*)buf, n, (EVP_PKEY*)data->key); } else err = 0; break; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "-- SMD Final alg=%d (%p) %d bytes--\n", data->alg, data->ctx, n)); DBGHEX(TEST, buf, n); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--")); /* return length of digest or signature produced */ if (len) *len = (int)n; } /* cleanup and free the HMAC or EVP_MD context */ if ((data->alg & (SOAP_SMD_PASSTHRU-1)) == SOAP_SMD_HMAC_SHA1) HMAC_CTX_cleanup((HMAC_CTX*)data->ctx); else EVP_MD_CTX_cleanup((EVP_MD_CTX*)data->ctx); SOAP_FREE(soap, data->ctx); data->ctx = NULL; /* check and return */ return soap_smd_check(soap, data, err, "soap_smd_final() failed"); }
/** @fn int soap_smd_final(struct soap *soap, struct soap_smd_data *data, char *buf, int *len) @brief Finalizes (signed) digest computation and returns digest or signature. @param soap context @param[in,out] data smdevp engine context @param[in] buf contains signature for verification (SOAP_SMD_VRFY algorithms) @param[out] buf is populated with the digest or signature @param[in] len points to length of signature to verify (SOAP_SMD_VRFY algorithms) @param[out] len points to length of stored digest or signature (pass NULL if you are not interested in this value) @return SOAP_OK or SOAP_SSL_ERROR */ int soap_smd_final(struct soap *soap, struct soap_smd_data *data, char *buf, int *len) { unsigned int n = 0; int ok = 1; if (!data->ctx) return soap_set_receiver_error(soap, "soap_smd_final() failed", "No context", SOAP_SSL_ERROR); if (buf) { /* finalize the digest or signature computation */ switch (data->alg & SOAP_SMD_ALGO) { case SOAP_SMD_HMAC: HMAC_Final((HMAC_CTX*)data->ctx, (unsigned char*)buf, &n); break; case SOAP_SMD_DGST: EVP_DigestFinal_ex((EVP_MD_CTX*)data->ctx, (unsigned char*)buf, &n); break; case SOAP_SMD_SIGN: ok = EVP_SignFinal((EVP_MD_CTX*)data->ctx, (unsigned char*)buf, &n, (EVP_PKEY*)data->key); break; case SOAP_SMD_VRFY: if (len) { n = (unsigned int)*len; ok = EVP_VerifyFinal((EVP_MD_CTX*)data->ctx, (unsigned char*)buf, n, (EVP_PKEY*)data->key); } else ok = 0; break; } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "-- SMD Final alg=%x (%p) %d bytes--\n", data->alg, data->ctx, n)); DBGHEX(TEST, buf, n); DBGLOG(TEST, SOAP_MESSAGE(fdebug, "\n--")); /* pass back length of digest or signature produced */ if (len) *len = (int)n; } /* cleanup */ if ((data->alg & SOAP_SMD_ALGO) == SOAP_SMD_HMAC) HMAC_CTX_cleanup((HMAC_CTX*)data->ctx); else EVP_MD_CTX_cleanup((EVP_MD_CTX*)data->ctx); SOAP_FREE(soap, data->ctx); data->ctx = NULL; /* check and return */ return soap_smd_check(soap, data, ok, "soap_smd_final() failed"); }
/** @fn int soap_smd_init(struct soap *soap, struct soap_smd_data *data, int alg, const void *key, int keylen) @brief Initiates a (signed) digest computation. @param soap context @param[in,out] data smdevp engine context @param[in] alg is algorithm to use @param[in] key is key to use or NULL for digests @param[in] keylen is length of HMAC key (when provided) @return SOAP_OK or SOAP_SSL_ERROR */ int soap_smd_init(struct soap *soap, struct soap_smd_data *data, int alg, const void *key, int keylen) { int ok = 1; const EVP_MD *type; soap_ssl_init(); /* the algorithm to use */ data->alg = alg; /* the key to use */ data->key = key; /* allocate and init the OpenSSL HMAC or EVP_MD context */ if ((alg & SOAP_SMD_ALGO) == SOAP_SMD_HMAC) { data->ctx = (void*)SOAP_MALLOC(soap, sizeof(HMAC_CTX)); if (!data->ctx) return soap_set_receiver_error(soap, "soap_smd_init() failed", "No context", SOAP_SSL_ERROR); HMAC_CTX_init((HMAC_CTX*)data->ctx); } else { data->ctx = (void*)SOAP_MALLOC(soap, sizeof(EVP_MD_CTX)); if (!data->ctx) return soap_set_receiver_error(soap, "soap_smd_init() failed", "No context", SOAP_SSL_ERROR); EVP_MD_CTX_init((EVP_MD_CTX*)data->ctx); } DBGLOG(TEST, SOAP_MESSAGE(fdebug, "-- SMD Init alg=%x (%p) --\n", alg, data->ctx)); /* init the digest or signature computations */ switch (alg & SOAP_SMD_HASH) { case SOAP_SMD_MD5: type = EVP_md5(); break; case SOAP_SMD_SHA1: type = EVP_sha1(); break; #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) case SOAP_SMD_SHA224: type = EVP_sha224(); break; case SOAP_SMD_SHA256: type = EVP_sha256(); break; case SOAP_SMD_SHA384: type = EVP_sha384(); break; case SOAP_SMD_SHA512: type = EVP_sha512(); break; #endif default: return soap_smd_check(soap, data, 0, "soap_smd_init() failed: cannot load digest"); } switch (alg & SOAP_SMD_ALGO) { case SOAP_SMD_HMAC: HMAC_Init((HMAC_CTX*)data->ctx, key, keylen, type); break; case SOAP_SMD_DGST: EVP_DigestInit((EVP_MD_CTX*)data->ctx, type); break; case SOAP_SMD_SIGN: ok = EVP_SignInit((EVP_MD_CTX*)data->ctx, type); break; case SOAP_SMD_VRFY: ok = EVP_VerifyInit((EVP_MD_CTX*)data->ctx, type); break; default: return soap_set_receiver_error(soap, "Unsupported digest algorithm", NULL, SOAP_SSL_ERROR); } /* check and return */ return soap_smd_check(soap, data, ok, "soap_smd_init() failed"); }