/** * Base16-encode data * * @v raw Raw data * @v len Length of raw data * @v encoded Buffer for encoded string * * The buffer must be the correct length for the encoded string. Use * something like * * char buf[ base16_encoded_len ( len ) + 1 ]; * * (the +1 is for the terminating NUL) to provide a buffer of the * correct size. */ void base16_encode ( const uint8_t *raw, size_t len, char *encoded ) { const uint8_t *raw_bytes = raw; char *encoded_bytes = encoded; size_t remaining = len; for ( ; remaining-- ; encoded_bytes += 2 ) { sprintf ( encoded_bytes, "%02x", *(raw_bytes++) ); } DBG ( "Base16-encoded to \"%s\":\n", encoded ); DBG_HDA ( 0, raw, len ); assert ( strlen ( encoded ) == base16_encoded_len ( len ) ); }
/** * Display status of a certificate * * @v cert X.509 certificate */ void certstat ( struct x509_certificate *cert ) { struct digest_algorithm *digest = &sha1_algorithm; uint8_t fingerprint[ digest->digestsize ]; char buf[ base16_encoded_len ( sizeof ( fingerprint ) ) + 1 /* NUL */ ]; /* Generate fingerprint */ x509_fingerprint ( cert, digest, fingerprint ); base16_encode ( fingerprint, sizeof ( fingerprint ), buf, sizeof ( buf ) ); /* Print certificate status */ printf ( "%s : %s", x509_name ( cert ), buf ); if ( cert->flags & X509_FL_PERMANENT ) printf ( " [PERMANENT]" ); if ( cert->flags & X509_FL_EXPLICIT ) printf ( " [EXPLICIT]" ); if ( x509_is_valid ( cert ) ) printf ( " [VALIDATED]" ); printf ( "\n" ); }
/** * Perform HTTP Digest authentication * * @v http HTTP transaction * @ret rc Return status code */ static int http_digest_authenticate ( struct http_transaction *http ) { struct http_request_auth *req = &http->request.auth; struct http_response_auth *rsp = &http->response.auth; char ha1[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ]; char ha2[ base16_encoded_len ( MD5_DIGEST_SIZE ) + 1 /* NUL */ ]; static const char md5sess[] = "MD5-sess"; static const char md5[] = "MD5"; struct md5_context ctx; /* Check for required response parameters */ if ( ! rsp->realm ) { DBGC ( http, "HTTP %p has no realm for Digest authentication\n", http ); return -EINVAL; } if ( ! rsp->nonce ) { DBGC ( http, "HTTP %p has no nonce for Digest authentication\n", http ); return -EINVAL; } /* Record username and password */ if ( ! http->uri->user ) { DBGC ( http, "HTTP %p has no username for Digest " "authentication\n", http ); return -EACCES_USERNAME; } req->username = http->uri->user; req->password = ( http->uri->password ? http->uri->password : "" ); /* Handle quality of protection */ if ( rsp->qop ) { /* Use "auth" in subsequent request */ req->qop = "auth"; /* Generate a client nonce */ snprintf ( req->cnonce, sizeof ( req->cnonce ), "%08lx", random() ); /* Determine algorithm */ req->algorithm = md5; if ( rsp->algorithm && ( strcasecmp ( rsp->algorithm, md5sess ) == 0 ) ) { req->algorithm = md5sess; } } /* Generate HA1 */ http_digest_init ( &ctx ); http_digest_update ( &ctx, req->username ); http_digest_update ( &ctx, rsp->realm ); http_digest_update ( &ctx, req->password ); http_digest_final ( &ctx, ha1, sizeof ( ha1 ) ); if ( req->algorithm == md5sess ) { http_digest_init ( &ctx ); http_digest_update ( &ctx, ha1 ); http_digest_update ( &ctx, rsp->nonce ); http_digest_update ( &ctx, req->cnonce ); http_digest_final ( &ctx, ha1, sizeof ( ha1 ) ); } /* Generate HA2 */ http_digest_init ( &ctx ); http_digest_update ( &ctx, http->request.method->name ); http_digest_update ( &ctx, http->request.uri ); http_digest_final ( &ctx, ha2, sizeof ( ha2 ) ); /* Generate response */ http_digest_init ( &ctx ); http_digest_update ( &ctx, ha1 ); http_digest_update ( &ctx, rsp->nonce ); if ( req->qop ) { http_digest_update ( &ctx, HTTP_DIGEST_NC ); http_digest_update ( &ctx, req->cnonce ); http_digest_update ( &ctx, req->qop ); } http_digest_update ( &ctx, ha2 ); http_digest_final ( &ctx, req->response, sizeof ( req->response ) ); return 0; }