/** * Build OCSP request * * @v ocsp OCSP check * @ret rc Return status code */ static int ocsp_request ( struct ocsp_check *ocsp ) { struct digest_algorithm *digest = &ocsp_digest_algorithm; struct asn1_builder *builder = &ocsp->request.builder; struct asn1_cursor *cert_id_tail = &ocsp->request.cert_id_tail; uint8_t digest_ctx[digest->ctxsize]; uint8_t name_digest[digest->digestsize]; uint8_t pubkey_digest[digest->digestsize]; int rc; /* Generate digests */ digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, ocsp->cert->issuer.raw.data, ocsp->cert->issuer.raw.len ); digest_final ( digest, digest_ctx, name_digest ); digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, ocsp->issuer->subject.public_key.raw_bits.data, ocsp->issuer->subject.public_key.raw_bits.len ); digest_final ( digest, digest_ctx, pubkey_digest ); /* Construct request */ if ( ( rc = ( asn1_prepend_raw ( builder, ocsp->cert->serial.raw.data, ocsp->cert->serial.raw.len ), asn1_prepend ( builder, ASN1_OCTET_STRING, pubkey_digest, sizeof ( pubkey_digest ) ), asn1_prepend ( builder, ASN1_OCTET_STRING, name_digest, sizeof ( name_digest ) ), asn1_prepend ( builder, ASN1_SEQUENCE, ocsp_algorithm_id, sizeof ( ocsp_algorithm_id ) ), asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ), asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n", ocsp, x509_name ( ocsp->cert ) ); DBGC2_HDA ( ocsp, 0, builder->data, builder->len ); /* Parse certificate ID for comparison with response */ cert_id_tail->data = builder->data; cert_id_tail->len = builder->len; if ( ( rc = ( asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_enter ( cert_id_tail, ASN1_SEQUENCE ), asn1_skip ( cert_id_tail, ASN1_SEQUENCE ) ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ) ); return rc; } return 0; }
/** * Test digest algorithm * * @v digest Digest algorithm * @v fragments Digest test fragment list, or NULL * @v data Test data * @v len Length of test data * @v expected Expected digest value * @ret ok Digest value is as expected */ int digest_test ( struct digest_algorithm *digest, struct digest_test_fragments *fragments, void *data, size_t len, void *expected ) { uint8_t ctx[digest->ctxsize]; uint8_t out[digest->digestsize]; size_t frag_len = 0; unsigned int i; /* Initialise digest */ digest_init ( digest, ctx ); /* Update digest fragment-by-fragment */ for ( i = 0 ; len && ( i < ( sizeof ( fragments->len ) / sizeof ( fragments->len[0] ) ) ) ; i++ ) { if ( fragments ) frag_len = fragments->len[i]; if ( ( frag_len == 0 ) || ( frag_len < len ) ) frag_len = len; digest_update ( digest, ctx, data, frag_len ); data += frag_len; len -= frag_len; } /* Finalise digest */ digest_final ( digest, ctx, out ); /* Compare against expected output */ return ( memcmp ( expected, out, sizeof ( out ) ) == 0 ); }
/** * Calculate digest algorithm cost * * @v digest Digest algorithm * @ret cost Cost (in cycles per byte) */ unsigned long digest_cost ( struct digest_algorithm *digest ) { static uint8_t random[8192]; /* Too large for stack */ uint8_t ctx[digest->ctxsize]; uint8_t out[digest->digestsize]; struct profiler profiler; unsigned long cost; unsigned int i; /* Fill buffer with pseudo-random data */ srand ( 0x1234568 ); for ( i = 0 ; i < sizeof ( random ) ; i++ ) random[i] = rand(); /* Profile digest calculation */ memset ( &profiler, 0, sizeof ( profiler ) ); for ( i = 0 ; i < PROFILE_COUNT ; i++ ) { profile_start ( &profiler ); digest_init ( digest, ctx ); digest_update ( digest, ctx, random, sizeof ( random ) ); digest_final ( digest, ctx, out ); profile_stop ( &profiler ); } /* Round to nearest whole number of cycles per byte */ cost = ( ( profile_mean ( &profiler ) + ( sizeof ( random ) / 2 ) ) / sizeof ( random ) ); return cost; }
int main(int argc, char *argv[]) { FILE *fd; char buf[8192]; int buflen; digestctx_t *ctx; if (argc < 2) { printf("Usage: %s digestmethod [filename]\n", argv[0]); printf("\"digestmethod\" is \"md5\", \"sha1\", \"sha256\", \"sha512\" or \"rmd160\"\n"); return 1; } if ((ctx = digest_init(argv[1])) == NULL) { printf("Unknown message digest method %s\n", argv[1]); return 1; } if (argc > 2) fd = fopen(argv[2], "r"); else fd = stdin; if (fd == NULL) { printf("Cannot open file %s\n", argv[2]); return 1; } while ((buflen = fread(buf, 1, sizeof(buf), fd)) > 0) { digest_data(ctx, buf, buflen); } printf("%s\n", digest_done(ctx)); return 0; }
/** * Compare responder's certificate public key hash * * @v ocsp OCSP check * @v cert Certificate * @ret difference Difference as returned by memcmp() */ static int ocsp_compare_responder_key_hash ( struct ocsp_check *ocsp, struct x509_certificate *cert ) { struct ocsp_responder *responder = &ocsp->response.responder; struct asn1_cursor key_hash; uint8_t ctx[SHA1_CTX_SIZE]; uint8_t digest[SHA1_DIGEST_SIZE]; int difference; /* Enter responder key hash */ memcpy ( &key_hash, &responder->id, sizeof ( key_hash ) ); asn1_enter ( &key_hash, ASN1_OCTET_STRING ); /* Sanity check */ difference = ( sizeof ( digest ) - key_hash.len ); if ( difference ) return difference; /* Generate SHA1 hash of certificate's public key */ digest_init ( &sha1_algorithm, ctx ); digest_update ( &sha1_algorithm, ctx, cert->subject.public_key.raw_bits.data, cert->subject.public_key.raw_bits.len ); digest_final ( &sha1_algorithm, ctx, digest ); /* Compare responder key hash with hash of certificate's public key */ return memcmp ( digest, key_hash.data, sizeof ( digest ) ); }
/** * Report server passphrase test result * * @v test Content information segment test * @v info Content information * @v pass Server passphrase * @v pass_len Length of server passphrase * @v file Test code file * @v line Test code line */ static void peerdist_info_passphrase_okx ( struct peerdist_info_segment_test *test, const struct peerdist_info *info, uint8_t *pass, size_t pass_len, const char *file, unsigned int line ) { struct digest_algorithm *digest = info->digest; uint8_t ctx[digest->ctxsize]; uint8_t secret[digest->digestsize]; uint8_t expected[digest->digestsize]; size_t digestsize = info->digestsize; size_t secretsize = digestsize; /* Calculate server secret */ digest_init ( digest, ctx ); digest_update ( digest, ctx, pass, pass_len ); digest_final ( digest, ctx, secret ); /* Calculate expected segment secret */ hmac_init ( digest, ctx, secret, &secretsize ); assert ( secretsize == digestsize ); hmac_update ( digest, ctx, test->expected_hash, digestsize ); hmac_final ( digest, ctx, secret, &secretsize, expected ); assert ( secretsize == digestsize ); /* Verify segment secret */ okx ( memcmp ( test->expected_secret, expected, digestsize ) == 0, file, line ); }
/** * Finalise HMAC * * @v digest Digest algorithm to use * @v digest_ctx Digest context * @v key Key * @v key_len Length of key * @v hmac HMAC digest to fill in * * The length of the key should be less than the block size of the * digest algorithm being used. (If the key length is greater, it * will be replaced with its own digest, and key_len will be updated * accordingly). */ void hmac_final ( struct digest_algorithm *digest, void *digest_ctx, void *key, size_t *key_len, void *hmac ) { unsigned char k_opad[digest->blocksize]; unsigned int i; /* Reduce key if necessary */ if ( *key_len > sizeof ( k_opad ) ) hmac_reduce_key ( digest, key, key_len ); /* Construct output pad */ memset ( k_opad, 0, sizeof ( k_opad ) ); memcpy ( k_opad, key, *key_len ); for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) { k_opad[i] ^= 0x5c; } /* Finish inner hash */ digest_final ( digest, digest_ctx, hmac ); /* Perform outer hash */ digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) ); digest_update ( digest, digest_ctx, hmac, digest->digestsize ); digest_final ( digest, digest_ctx, hmac ); }
/** * Reduce HMAC key length * * @v digest Digest algorithm to use * @v digest_ctx Digest context * @v key Key * @v key_len Length of key */ static void hmac_reduce_key ( struct digest_algorithm *digest, void *key, size_t *key_len ) { uint8_t digest_ctx[digest->ctxsize]; digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, key, *key_len ); digest_final ( digest, digest_ctx, key ); *key_len = digest->digestsize; }
/** * The "digest" command * * @v argc Argument count * @v argv Argument list * @v digest Digest algorithm * @ret rc Exit code */ static int digest_exec ( int argc, char **argv, struct digest_algorithm *digest ) { const char *image_name; struct image *image; uint8_t digest_ctx[digest->ctxsize]; uint8_t digest_out[digest->digestsize]; uint8_t buf[128]; size_t offset; size_t len; size_t frag_len; int i; unsigned j; if ( argc < 2 || !strcmp ( argv[1], "--help" ) || !strcmp ( argv[1], "-h" ) ) { digest_syntax ( argv ); return 1; } for ( i = 1 ; i < argc ; i++ ) { image_name = argv[i]; /* find image */ image = find_image ( image_name ); if ( ! image ) { printf ( "No such image: %s\n", image_name ); continue; } offset = 0; len = image->len; /* calculate digest */ digest_init ( digest, digest_ctx ); while ( len ) { frag_len = len; if ( frag_len > sizeof ( buf ) ) frag_len = sizeof ( buf ); copy_from_user ( buf, image->data, offset, frag_len ); digest_update ( digest, digest_ctx, buf, frag_len ); len -= frag_len; offset += frag_len; } digest_final ( digest, digest_ctx, digest_out ); for ( j = 0 ; j < sizeof ( digest_out ) ; j++ ) printf ( "%02x", digest_out[j] ); printf ( " %s\n", image->name ); } return 0; }
/** * Check OCSP response signature * * @v ocsp OCSP check * @v signer Signing certificate * @ret rc Return status code */ static int ocsp_check_signature ( struct ocsp_check *ocsp, struct x509_certificate *signer ) { struct ocsp_response *response = &ocsp->response; struct digest_algorithm *digest = response->algorithm->digest; struct pubkey_algorithm *pubkey = response->algorithm->pubkey; struct x509_public_key *public_key = &signer->subject.public_key; uint8_t digest_ctx[ digest->ctxsize ]; uint8_t digest_out[ digest->digestsize ]; uint8_t pubkey_ctx[ pubkey->ctxsize ]; int rc; /* Generate digest */ digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, response->tbs.data, response->tbs.len ); digest_final ( digest, digest_ctx, digest_out ); /* Initialise public-key algorithm */ if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, public_key->raw.len ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); goto err_init; } /* Verify digest */ if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, response->signature.data, response->signature.len ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); goto err_verify; } DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n", ocsp, x509_name ( ocsp->cert ) ); err_verify: pubkey_final ( pubkey, pubkey_ctx ); err_init: return rc; }
/** * Initialise HMAC * * @v digest Digest algorithm to use * @v digest_ctx Digest context * @v key Key * @v key_len Length of key * * The length of the key should be less than the block size of the * digest algorithm being used. (If the key length is greater, it * will be replaced with its own digest, and key_len will be updated * accordingly). */ void hmac_init ( struct digest_algorithm *digest, void *digest_ctx, void *key, size_t *key_len ) { unsigned char k_ipad[digest->blocksize]; unsigned int i; /* Reduce key if necessary */ if ( *key_len > sizeof ( k_ipad ) ) hmac_reduce_key ( digest, key, key_len ); /* Construct input pad */ memset ( k_ipad, 0, sizeof ( k_ipad ) ); memcpy ( k_ipad, key, *key_len ); for ( i = 0 ; i < sizeof ( k_ipad ) ; i++ ) { k_ipad[i] ^= 0x36; } /* Start inner hash */ digest_init ( digest, digest_ctx ); digest_update ( digest, digest_ctx, k_ipad, sizeof ( k_ipad ) ); }
char *filesum(char *fn, char *dtype) { static char *result = NULL; digestctx_t *ctx; FILE *fd; unsigned char buf[8192]; int openerr, buflen; if ((ctx = digest_init(dtype)) == NULL) return ""; fd = fileopen(fn, &openerr); if (fd == NULL) return ""; while ((buflen = fread(buf, 1, sizeof(buf), fd)) > 0) digest_data(ctx, buf, buflen); fclose(fd); if (result) xfree(result); result = strdup(digest_done(ctx)); return result; }
static int digest_copy(EVP_MD_CTX *to, const EVP_MD_CTX *from) { struct digest_ctx *digest_from = (struct digest_ctx *)EVP_MD_CTX_md_data(from); struct digest_ctx *digest_to = (struct digest_ctx *)EVP_MD_CTX_md_data(to); struct cphash_op cphash; if (digest_from == NULL || digest_from->init_called != 1) return 1; if (!digest_init(to)) { SYSerr(SYS_F_IOCTL, errno); return 0; } cphash.src_ses = digest_from->sess.ses; cphash.dst_ses = digest_to->sess.ses; if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) { SYSerr(SYS_F_IOCTL, errno); return 0; } return 1; }
void add_http_test(testitem_t *t) { http_data_t *httptest; char *dnsip = NULL; ssloptions_t *sslopt = NULL; char *sslopt_ciphers = NULL; int sslopt_version = SSLVERSION_DEFAULT; char *sslopt_clientcert = NULL; int httpversion = HTTPVER_11; cookielist_t *ck = NULL; int firstcookie = 1; char *decodedurl; strbuffer_t *httprequest = newstrbuffer(0); /* Allocate the private data and initialize it */ httptest = (http_data_t *) calloc(1, sizeof(http_data_t)); t->privdata = (void *) httptest; decodedurl = decode_url(t->testspec, &httptest->weburl); if (!decodedurl) { errprintf("Invalid URL for http check: %s\n", t->testspec); return; } httptest->url = strdup(decodedurl); httptest->contlen = -1; httptest->parsestatus = (httptest->weburl.proxyurl ? httptest->weburl.proxyurl->parseerror : httptest->weburl.desturl->parseerror); /* If there was a parse error in the URL, dont run the test */ if (httptest->parsestatus) return; if (httptest->weburl.proxyurl && (httptest->weburl.proxyurl->ip == NULL)) { dnsip = dnsresolve(httptest->weburl.proxyurl->host); if (dnsip) { httptest->weburl.proxyurl->ip = strdup(dnsip); } else { dbgprintf("Could not resolve URL hostname '%s'\n", httptest->weburl.proxyurl->host); } } else if (httptest->weburl.desturl->ip == NULL) { dnsip = dnsresolve(httptest->weburl.desturl->host); if (dnsip) { httptest->weburl.desturl->ip = strdup(dnsip); } else { dbgprintf("Could not resolve URL hostname '%s'\n", httptest->weburl.desturl->host); } } switch (httptest->weburl.testtype) { case WEBTEST_PLAIN: case WEBTEST_STATUS: httptest->contentcheck = CONTENTCHECK_NONE; break; case WEBTEST_CONTENT: { FILE *contentfd; char contentfn[PATH_MAX]; sprintf(contentfn, "%s/content/%s.substring", xgetenv("XYMONHOME"), commafy(t->host->hostname)); contentfd = fopen(contentfn, "r"); if (contentfd) { char l[MAX_LINE_LEN]; char *p; if (fgets(l, sizeof(l), contentfd)) { p = strchr(l, '\n'); if (p) { *p = '\0'; }; httptest->weburl.expdata = strdup(l); } else { httptest->contstatus = STATUS_CONTENTMATCH_NOFILE; } fclose(contentfd); } else { httptest->contstatus = STATUS_CONTENTMATCH_NOFILE; } httptest->contentcheck = CONTENTCHECK_REGEX; } break; case WEBTEST_CONT: httptest->contentcheck = ((*httptest->weburl.expdata == '#') ? CONTENTCHECK_DIGEST : CONTENTCHECK_REGEX); break; case WEBTEST_NOCONT: httptest->contentcheck = CONTENTCHECK_NOREGEX; break; case WEBTEST_POST: case WEBTEST_SOAP: if (httptest->weburl.expdata == NULL) { httptest->contentcheck = CONTENTCHECK_NONE; } else { httptest->contentcheck = ((*httptest->weburl.expdata == '#') ? CONTENTCHECK_DIGEST : CONTENTCHECK_REGEX); } break; case WEBTEST_NOPOST: case WEBTEST_NOSOAP: if (httptest->weburl.expdata == NULL) { httptest->contentcheck = CONTENTCHECK_NONE; } else { httptest->contentcheck = CONTENTCHECK_NOREGEX; } break; case WEBTEST_TYPE: httptest->contentcheck = CONTENTCHECK_CONTENTTYPE; break; } /* Compile the hashes and regex's for those tests that use it */ switch (httptest->contentcheck) { case CONTENTCHECK_DIGEST: { char *hashfunc; httptest->exp = (void *) strdup(httptest->weburl.expdata+1); hashfunc = strchr(httptest->exp, ':'); if (hashfunc) { *hashfunc = '\0'; httptest->digestctx = digest_init(httptest->exp); *hashfunc = ':'; } } break; case CONTENTCHECK_REGEX: case CONTENTCHECK_NOREGEX: { int status; httptest->exp = (void *) malloc(sizeof(regex_t)); status = regcomp((regex_t *)httptest->exp, httptest->weburl.expdata, REG_EXTENDED|REG_NOSUB); if (status) { errprintf("Failed to compile regexp '%s' for URL %s\n", httptest->weburl.expdata, httptest->url); httptest->contstatus = STATUS_CONTENTMATCH_BADREGEX; } } break; case CONTENTCHECK_CONTENTTYPE: httptest->exp = httptest->weburl.expdata; break; } if (httptest->weburl.desturl->schemeopts) { if (strstr(httptest->weburl.desturl->schemeopts, "3")) sslopt_version = SSLVERSION_V3; else if (strstr(httptest->weburl.desturl->schemeopts, "2")) sslopt_version = SSLVERSION_V2; if (strstr(httptest->weburl.desturl->schemeopts, "h")) sslopt_ciphers = ciphershigh; else if (strstr(httptest->weburl.desturl->schemeopts, "m")) sslopt_ciphers = ciphersmedium; if (strstr(httptest->weburl.desturl->schemeopts, "10")) httpversion = HTTPVER_10; else if (strstr(httptest->weburl.desturl->schemeopts, "11")) httpversion = HTTPVER_11; } /* Get any cookies */ load_cookies(); /* Generate the request */ addtobuffer(httprequest, (httptest->weburl.postdata ? "POST " : "GET ")); switch (httpversion) { case HTTPVER_10: addtobuffer(httprequest, (httptest->weburl.proxyurl ? httptest->url : httptest->weburl.desturl->relurl)); addtobuffer(httprequest, " HTTP/1.0\r\n"); break; case HTTPVER_11: /* * Experience shows that even though HTTP/1.1 says you should send the * full URL, some servers (e.g. SunOne App server 7) choke on it. * So just send the good-old relative URL unless we're proxying. */ addtobuffer(httprequest, (httptest->weburl.proxyurl ? httptest->url : httptest->weburl.desturl->relurl)); addtobuffer(httprequest, " HTTP/1.1\r\n"); addtobuffer(httprequest, "Connection: close\r\n"); break; } addtobuffer(httprequest, "Host: "); addtobuffer(httprequest, httptest->weburl.desturl->host); if ((httptest->weburl.desturl->port != 80) && (httptest->weburl.desturl->port != 443)) { char hostporthdr[20]; sprintf(hostporthdr, ":%d", httptest->weburl.desturl->port); addtobuffer(httprequest, hostporthdr); } addtobuffer(httprequest, "\r\n"); if (httptest->weburl.postdata) { char hdr[100]; int contlen = strlen(httptest->weburl.postdata); if (strncmp(httptest->weburl.postdata, "file:", 5) == 0) { /* Load the POST data from a file */ FILE *pf = fopen(httptest->weburl.postdata+5, "r"); if (pf == NULL) { errprintf("Cannot open POST data file %s\n", httptest->weburl.postdata+5); xfree(httptest->weburl.postdata); httptest->weburl.postdata = strdup(""); contlen = 0; } else { struct stat st; if (fstat(fileno(pf), &st) == 0) { int n; xfree(httptest->weburl.postdata); httptest->weburl.postdata = (char *)malloc(st.st_size + 1); *(httptest->weburl.postdata) = '\0'; n = fread(httptest->weburl.postdata, 1, st.st_size, pf); if (n == st.st_size) { *(httptest->weburl.postdata+n) = '\0'; contlen = n; } else { errprintf("Cannot read file %s: %s\n", httptest->weburl.postdata+5, strerror(errno)); contlen = 0; } } else { errprintf("Cannot stat file %s\n", httptest->weburl.postdata+5); httptest->weburl.postdata = strdup(""); contlen = 0; } fclose(pf); } } addtobuffer(httprequest, "Content-type: "); if (httptest->weburl.postcontenttype) addtobuffer(httprequest, httptest->weburl.postcontenttype); else if ((httptest->weburl.testtype == WEBTEST_SOAP) || (httptest->weburl.testtype == WEBTEST_NOSOAP)) addtobuffer(httprequest, "application/soap+xml; charset=utf-8"); else addtobuffer(httprequest, "application/x-www-form-urlencoded"); addtobuffer(httprequest, "\r\n"); sprintf(hdr, "Content-Length: %d\r\n", contlen); addtobuffer(httprequest, hdr); } { char useragent[100]; void *hinfo; char *browser = NULL; hinfo = hostinfo(t->host->hostname); if (hinfo) browser = xmh_item(hinfo, XMH_BROWSER); if (browser) { sprintf(useragent, "User-Agent: %s\r\n", browser); } else { sprintf(useragent, "User-Agent: Xymon xymonnet/%s\r\n", VERSION); } addtobuffer(httprequest, useragent); } if (httptest->weburl.desturl->auth) { if (strncmp(httptest->weburl.desturl->auth, "CERT:", 5) == 0) { sslopt_clientcert = httptest->weburl.desturl->auth+5; } else { addtobuffer(httprequest, "Authorization: Basic "); addtobuffer(httprequest, base64encode(httptest->weburl.desturl->auth)); addtobuffer(httprequest, "\r\n"); } } if (httptest->weburl.proxyurl && httptest->weburl.proxyurl->auth) { addtobuffer(httprequest, "Proxy-Authorization: Basic "); addtobuffer(httprequest, base64encode(httptest->weburl.proxyurl->auth)); addtobuffer(httprequest, "\r\n"); } for (ck = cookiehead; (ck); ck = ck->next) { int useit = 0; if (ck->tailmatch) { int startpos = strlen(httptest->weburl.desturl->host) - strlen(ck->host); if (startpos > 0) useit = (strcmp(httptest->weburl.desturl->host+startpos, ck->host) == 0); } else useit = (strcmp(httptest->weburl.desturl->host, ck->host) == 0); if (useit) useit = (strncmp(ck->path, httptest->weburl.desturl->relurl, strlen(ck->path)) == 0); if (useit) { if (firstcookie) { addtobuffer(httprequest, "Cookie: "); firstcookie = 0; } addtobuffer(httprequest, ck->name); addtobuffer(httprequest, "="); addtobuffer(httprequest, ck->value); addtobuffer(httprequest, "\r\n"); } } /* Some standard stuff */ addtobuffer(httprequest, "Accept: */*\r\n"); addtobuffer(httprequest, "Pragma: no-cache\r\n"); if ((httptest->weburl.testtype == WEBTEST_SOAP) || (httptest->weburl.testtype == WEBTEST_NOSOAP)) { /* Must provide a SOAPAction header */ addtobuffer(httprequest, "SOAPAction: "); addtobuffer(httprequest, httptest->url); addtobuffer(httprequest, "\r\n"); } /* The final blank line terminates the headers */ addtobuffer(httprequest, "\r\n"); /* Post data goes last */ if (httptest->weburl.postdata) addtobuffer(httprequest, httptest->weburl.postdata); /* Pickup any SSL options the user wants */ if (sslopt_ciphers || (sslopt_version != SSLVERSION_DEFAULT) || sslopt_clientcert){ sslopt = (ssloptions_t *) malloc(sizeof(ssloptions_t)); sslopt->cipherlist = sslopt_ciphers; sslopt->sslversion = sslopt_version; sslopt->clientcert = sslopt_clientcert; } /* Add to TCP test queue */ if (httptest->weburl.proxyurl == NULL) { httptest->tcptest = add_tcp_test(httptest->weburl.desturl->ip, httptest->weburl.desturl->port, httptest->weburl.desturl->scheme, sslopt, t->srcip, t->testspec, t->silenttest, grabstrbuffer(httprequest), httptest, tcp_http_data_callback, tcp_http_final_callback); } else { httptest->tcptest = add_tcp_test(httptest->weburl.proxyurl->ip, httptest->weburl.proxyurl->port, httptest->weburl.proxyurl->scheme, sslopt, t->srcip, t->testspec, t->silenttest, grabstrbuffer(httprequest), httptest, tcp_http_data_callback, tcp_http_final_callback); } }
/** * Distribute entropy throughout a buffer * * @v hash Underlying hash algorithm * @v input Input data * @v input_len Length of input data, in bytes * @v output Output buffer * @v output_len Length of output buffer, in bytes * * This is the Hash_df function defined in ANS X9.82 Part 3-2007 * Section 10.5.2 (NIST SP 800-90 Section 10.4.1). * * The number of bits requested is implicit in the length of the * output buffer. Requests must be for an integral number of bytes. * * The output buffer is filled incrementally with each iteration of * the central loop, rather than constructing an overall "temp" and * then taking the leftmost(no_of_bits_to_return) bits. * * There is no way for the Hash_df function to fail. The returned * status SUCCESS is implicit. */ void hash_df ( struct digest_algorithm *hash, const void *input, size_t input_len, void *output, size_t output_len ) { uint8_t context[hash->ctxsize]; uint8_t digest[hash->digestsize]; size_t frag_len; struct { uint8_t pad[3]; uint8_t counter; uint32_t no_of_bits_to_return; } __attribute__ (( packed )) prefix; void *temp; size_t remaining; DBGC ( &hash_df, "HASH_DF input:\n" ); DBGC_HDA ( &hash_df, 0, input, input_len ); /* Sanity checks */ assert ( input != NULL ); assert ( output != NULL ); /* 1. temp = the Null string * 2. len = ceil ( no_of_bits_to_return / outlen ) * * (Nothing to do. We fill the output buffer incrementally, * rather than constructing the complete "temp" in-memory. * "len" is implicit in the number of iterations required to * fill the output buffer, and so is not calculated * explicitly.) */ /* 3. counter = an 8-bit binary value representing the integer "1" */ prefix.counter = 1; /* 4. For i = 1 to len do */ for ( temp = output, remaining = output_len ; remaining > 0 ; ) { /* Comment: in step 5.1 (sic), no_of_bits_to_return is * used as a 32-bit string. * * 4.1 temp = temp || Hash ( counter || no_of_bits_to_return * || input_string ) */ prefix.no_of_bits_to_return = htonl ( output_len * 8 ); digest_init ( hash, context ); digest_update ( hash, context, &prefix.counter, ( sizeof ( prefix ) - offsetof ( typeof ( prefix ), counter ) ) ); digest_update ( hash, context, input, input_len ); digest_final ( hash, context, digest ); /* 4.2 counter = counter + 1 */ prefix.counter++; /* 5. requested_bits = Leftmost ( no_of_bits_to_return ) * of temp * * (We fill the output buffer incrementally.) */ frag_len = sizeof ( digest ); if ( frag_len > remaining ) frag_len = remaining; memcpy ( temp, digest, frag_len ); temp += frag_len; remaining -= frag_len; } /* 6. Return SUCCESS and requested_bits */ DBGC ( &hash_df, "HASH_DF output:\n" ); DBGC_HDA ( &hash_df, 0, output, output_len ); return; }
int main(int argc, char *argv[]) { char srcfn[PATH_MAX]; char destfn[PATH_MAX]; char *p; struct stat st; unsigned char *sumbuf = NULL; if (argc > 2) { if (stat(argv[2], &st) == 0) { FILE *sumfd; printf("Loading md5-data ... "); sumfd = fopen(argv[2], "r"); if (sumfd) { sumbuf = (char *)malloc(st.st_size + 1); if (fread(sumbuf, 1, st.st_size, sumfd) == st.st_size) { printf("OK\n"); } else { printf("failed\n"); free(sumbuf); sumbuf = NULL; } fclose(sumfd); } else { printf("failed\n"); } } } while (fgets(srcfn, sizeof(srcfn), stdin)) { FILE *fd; unsigned char buf[8192]; size_t buflen; digestctx_t *ctx; char srcmd5[40]; char *md5sum; p = strchr(srcfn, '\n'); if (p) *p = '\0'; strcpy(destfn, argv[1]); p = srcfn; if (strcmp(srcfn, ".") == 0) p = ""; else if (strncmp(p, "./", 2) == 0) p += 2; strcat(destfn, p); *srcmd5 = '\0'; if (((fd = fopen(srcfn, "r")) != NULL) && ((ctx = digest_init("md5")) != NULL)) { while ((buflen = fread(buf, 1, sizeof(buf), fd)) > 0) digest_data(ctx, buf, buflen); strcpy(srcmd5, digest_done(ctx)); fclose(fd); } if (stat(destfn, &st) == 0) { /* Destination file exists, see if it's a previous version */ if (sumbuf == NULL) continue; /* No md5-data, don't overwrite an existing file */ if (!S_ISREG(st.st_mode)) continue; fd = fopen(destfn, "r"); if (fd == NULL) continue; if ((ctx = digest_init("md5")) == NULL) continue; while ((buflen = fread(buf, 1, sizeof(buf), fd)) > 0) digest_data(ctx, buf, buflen); md5sum = digest_done(ctx); fclose(fd); if (strstr(sumbuf, md5sum) == NULL) continue; /* Not one of our known versions */ if (strcmp(srcmd5, md5sum) == 0) continue; /* Already installed */ /* We now know the destination that exists is just one of our old files */ printf("Updating old standard file %s\n", destfn); unlink(destfn); } else { printf("Installing new file %s\n", destfn); } if (lstat(srcfn, &st) != 0) { printf("Error - cannot lstat() %s\n", srcfn); return 1; } if (S_ISREG(st.st_mode)) { FILE *infd, *outfd; char buf[16384]; int n; infd = fopen(srcfn, "r"); if (infd == NULL) { /* Don't know how this can happen, but .. */ fprintf(stderr, "Cannot open input file %s: %s\n", srcfn, strerror(errno)); return 1; } outfd = fopen(destfn, "w"); if (outfd == NULL) { /* Don't know how this can happen, but .. */ fprintf(stderr, "Cannot create output file %s: %s\n", destfn, strerror(errno)); return 1; } fchmod(fileno(outfd), S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); while ( (n = fread(buf, 1, sizeof(buf), infd)) > 0) fwrite(buf, 1, n, outfd); fclose(infd); fclose(outfd); } else if (S_ISDIR(st.st_mode)) { struct stat tmpst; /* Create upper-lying directories */ if (*destfn == '/') p = strchr(destfn+1, '/'); else p = strchr(destfn, '/'); while (p) { *p = '\0'; if ((stat(destfn, &tmpst) == 0) || (mkdir(destfn, st.st_mode) == 0)) { *p = '/'; p = strchr(p+1, '/'); } else p = NULL; } /* Create the directory itself */ if (stat(destfn, &tmpst) == -1) mkdir(destfn, st.st_mode); chmod(destfn, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); } else if (S_ISLNK(st.st_mode)) { char ldest[PATH_MAX + 1]; memset(ldest, 0, sizeof(ldest)); if ((readlink(srcfn, ldest, sizeof(ldest)-1) != -1) && (symlink(ldest, destfn) == 0)) {}; } } return 0; }
/** * Initialise HTTP Digest * * @v ctx Digest context * @v string Initial string */ static void http_digest_init ( struct md5_context *ctx ) { /* Initialise MD5 digest */ digest_init ( &md5_algorithm, ctx ); }