static int digest_tlsa_usage(EVP_MD_CTX * mdctx, TLS_TLSA *tlsa, const char *usage) { char **dgst; int ok = 1; for (digest_string(usage); tlsa; tlsa = tlsa->next) { digest_string(tlsa->mdalg); digest_tlsa_argv(tlsa, pkeys); digest_tlsa_argv(tlsa, certs); } return (ok); }
SEXP R_digest(SEXP x, SEXP algo){ if(!isString(x)) error("Argument 'x' must be a character vector."); if(!isString(algo)) error("Argument 'algo' must be a character vector."); int len = length(x); SEXP out = PROTECT(allocVector(STRSXP, len)); for (int i = 0; i < len; i++) { /* check for NA */ if(STRING_ELT(x, i) == NA_STRING) { SET_STRING_ELT(out, i, NA_STRING); continue; } /* create hash */ const char* str = CHAR(STRING_ELT(x, i)); unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len = digest_string(str, CHAR(asChar(algo)), strlen(str), md_value); /* create character vector */ char mdString[2*md_len+1]; for (int i = 0; i < md_len; i++) { sprintf(&mdString[i*2], "%02x", (unsigned int) md_value[i]); } mdString[2*md_len] = '\0'; SET_STRING_ELT(out, i, mkChar(mdString)); } UNPROTECT(1); return out; }
static bool file_read_chunk(unsigned char *chunk, const unsigned char *digest, void *db_info) { struct db *db = db_info; unsigned char *db_chunk; bool status = false; flock(db->fd, LOCK_SH); db_chunk = lookup_chunk(db, digest); if (db_chunk) { if (IS_ERR(db_chunk)) { TRACE("digest=%s: %s\n", digest_string(digest), strerror(PTR_ERR(db_chunk))); } else { status = true; memcpy(chunk, db_chunk, CHUNK_SIZE); unmap_chunk(db_chunk); } } flock(db->fd, LOCK_UN); return status; }
static bool write_chunk_sqlite(const unsigned char *chunk, const unsigned char *digest, void *db_info_ptr) { static const char sql[] = "INSERT OR IGNORE INTO chunk(hash, data) VALUES(?,?)"; struct db_info *db_info = db_info_ptr; sqlite3_stmt *stmt; int err; lock_db(db_info); err = sqlite3_prepare(db_info->db, sql, -1, &stmt, 0); if (err != SQLITE_OK) { ERROR("sqlite3_prepare failed: %s\n", sqlite3_errmsg(db_info->db)); unlock_db(db_info); return false; } sqlite3_bind_text(stmt, 1, digest_string(digest), -1, SQLITE_STATIC); sqlite3_bind_blob(stmt, 2, chunk, CHUNK_SIZE, SQLITE_STATIC); err = sqlite3_step(stmt); assert(err != SQLITE_ROW); if (sqlite3_finalize(stmt) != SQLITE_OK) { ERROR("sqlite3_finalize failed: %s\n", sqlite3_errmsg(db_info->db)); unlock_db(db_info); return false; } unlock_db(db_info); return true; }
static bool file_write_chunk(const unsigned char *chunk, const unsigned char *digest, void *db_info) { struct db *db = db_info; unsigned char *db_chunk; bool status = false; int error; flock(db->fd, LOCK_EX); db_chunk = lookup_chunk(db, digest); if (db_chunk) { if (IS_ERR(db_chunk)) { TRACE("lookup_chunk(%s): %s\n", digest_string(digest), strerror(PTR_ERR(db_chunk))); } else status = true; goto out; } /* * When adding a new chunk, the file needs to be resized, otherwise * any access to the chunk will cause a SIGBUS. */ if (ftruncate(db->fd, ((off_t)db->next_nr + 1) * CHUNK_SIZE)) { TRACE("ftruncate(%u * CHUNK_SIZE): %s\n", db->next_nr + 1, strerror(errno)); goto out; } db_chunk = __map_chunk(db, db->next_nr, 0); if (IS_ERR(db_chunk)) { TRACE("__map_chunk(%u): %s\n", db->next_nr, strerror(PTR_ERR(db_chunk))); goto out; } memcpy(db_chunk, chunk, CHUNK_SIZE); error = hash_insert(db, *(uint32_t *)digest, db->next_nr); if (error) { TRACE("hash_insert(0x%x, %u): %s\n", *(uint32_t *)digest, db->next_nr, strerror(-error)); goto out; } status = true; db->next_nr ++; out: unmap_chunk(db_chunk); flock(db->fd, LOCK_UN); return status; }
void R_digest_C( char ** Txt, int * Algo, int * Length, char ** Output) { static char *output, buf[41]; output = digest_string(*Txt, *Algo, *Length, buf); if(output == NULL && error_message != NULL) *Txt = error_message; else *Output = output; }
static bool read_chunk_sqlite(unsigned char *chunk, const unsigned char *digest, void *db_info_ptr) { static const char sql[] = "SELECT data FROM chunk WHERE hash = ?"; struct db_info *db_info = db_info_ptr; sqlite3_stmt *stmt; int err; bool status = false; lock_db(db_info); err = sqlite3_prepare(db_info->db, sql, -1, &stmt, 0); if (err != SQLITE_OK) { ERROR("sqlite3_prepare failed: %d\n", sqlite3_errmsg(db_info->db)); unlock_db(db_info); return false; } TRACE("%s\n", digest_string(digest)); sqlite3_bind_text(stmt, 1, digest_string(digest), -1, SQLITE_STATIC); err = sqlite3_step(stmt); if (err != SQLITE_ROW) { ERROR("sqlite3_step failed: %s\n", sqlite3_errmsg(db_info->db)); } else if (sqlite3_column_bytes(stmt, 0) != CHUNK_SIZE) { ERROR("sqlite3 query returned %d bytes instead of %d.\n", sqlite3_column_bytes(stmt, 0), CHUNK_SIZE); } else { TRACE("sqlite3 query got chunk.\n"); memcpy(chunk, sqlite3_column_blob(stmt, 0), CHUNK_SIZE); status = true; } sqlite3_finalize(stmt); unlock_db(db_info); return status; }
SEXP R_digest_raw(SEXP x, SEXP algo){ /* Check inputs */ if(TYPEOF(x) != RAWSXP) error("Argument 'x' must be a raw vector."); /* Convert the Raw vector to an unsigned char */ unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len = digest_string((const char*) RAW(x), CHAR(asChar(algo)), length(x), md_value); /* create raw output vector */ SEXP out = PROTECT(allocVector(RAWSXP, md_len)); memcpy(RAW(out), md_value, md_len); UNPROTECT(1); return out; }
SEXP R_digest( SEXP Txt, SEXP Algo, SEXP Length) { char *txt = (char *)STRING_VALUE(Txt); int algo = INTEGER_VALUE(Algo); int length = INTEGER_VALUE(Length); SEXP result = R_NilValue; static char *output, buf[41]; output = digest_string(txt, algo, length, buf); if(output == NULL) { error("Error in C computations of digest: %s", (error_message == NULL) ? "<unspecified error>" : error_message); return result; } PROTECT(result=allocVector(STRSXP, 1)); SET_STRING_ELT(result, 0, mkChar(output)); UNPROTECT(1); return result; }
char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask, const char *ciphers) { EVP_MD_CTX *mdctx; const EVP_MD *md; const char *mdalg; unsigned char md_buf[EVP_MAX_MD_SIZE]; unsigned int md_len; int ok = 1; int i; long sslversion; VSTRING *result; /* * Try to use sha256: our serverid choice should be strong enough to * resist 2nd-preimage attacks with a difficulty comparable to that of * DANE TLSA digests. Failing that, we compute serverid digests with the * default digest, but DANE requires sha256 and sha512, so if we must * fall back to our default digest, DANE support won't be available. We * panic if the fallback algorithm is not available, as it was verified * available in tls_client_init() and must not simply vanish. */ if ((md = EVP_get_digestbyname(mdalg = "sha256")) == 0 && (md = EVP_get_digestbyname(mdalg = props->mdalg)) == 0) msg_panic("digest algorithm \"%s\" not found", mdalg); /* Salt the session lookup key with the OpenSSL runtime version. */ sslversion = SSLeay(); mdctx = EVP_MD_CTX_create(); checkok(EVP_DigestInit_ex(mdctx, md, NULL)); digest_string(props->helo ? props->helo : ""); digest_object(&sslversion); digest_object(&protomask); digest_string(ciphers); /* * All we get from the session cache is a single bit telling us whether * the certificate is trusted or not, but we need to know whether the * trust is CA-based (in that case we must do name checks) or whether it * is a direct end-point match. We mustn't confuse the two, so it is * best to process only TA trust in the verify callback and check the EE * trust after. This works since re-used sessions always have access to * the leaf certificate, while only the original session has the leaf and * the full trust chain. * * Only the trust anchor matchlist is hashed into the session key. The end * entity certs are not used to determine whether a certificate is * trusted or not, rather these are rechecked against the leaf cert * outside the verification callback, each time a session is created or * reused. * * Therefore, the security context of the session does not depend on the EE * matching data, which is checked separately each time. So we exclude * the EE part of the DANE structure from the serverid digest. * * If the security level is "dane", we send SNI information to the peer. * This may cause it to respond with a non-default certificate. Since * certificates for sessions with no or different SNI data may not match, * we must include the SNI name in the session id. */ if (props->dane) { int mixed = (props->dane->flags & TLS_DANE_FLAG_MIXED); digest_object(&mixed); digest_dane(props->dane, ta); #if 0 digest_dane(props->dane, ee); /* See above */ #endif digest_string(props->tls_level == TLS_LEV_DANE ? props->host : ""); } checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len)); EVP_MD_CTX_destroy(mdctx); if (!ok) msg_fatal("error computing %s message digest", mdalg); /* Check for OpenSSL contract violation */ if (md_len > EVP_MAX_MD_SIZE) msg_panic("unexpectedly large %s digest size: %u", mdalg, md_len); /* * Append the digest to the serverid. We don't compare this digest to * any user-specified fingerprints. Therefore, we don't need to use a * colon-separated format, which saves space in the TLS session cache and * makes logging of session cache lookup keys more readable. * * This does however duplicate a few lines of code from the digest encoder * for colon-separated cert and pkey fingerprints. If that is a * compelling reason to consolidate, we could use that and append the * result. */ result = vstring_alloc(strlen(props->serverid) + 1 + 2 * md_len); vstring_strcpy(result, props->serverid); VSTRING_ADDCH(result, '&'); for (i = 0; i < md_len; i++) { VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0xf0) >> 4U]); VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0x0f)]); } VSTRING_TERMINATE(result); return (vstring_export(result)); }