WvStreams
|
00001 #include "wvocsp.h" 00002 #include "wvsslhacks.h" 00003 00004 static const int OCSP_MAX_VALIDITY_PERIOD = (5 * 60); // 5 min: openssl default 00005 00006 00007 WvOCSPReq::WvOCSPReq(const WvX509 &cert, const WvX509 &issuer) 00008 { 00009 wvssl_init(); 00010 00011 req = OCSP_REQUEST_new(); 00012 assert(req); 00013 00014 if (cert.isok() && issuer.isok()) 00015 { 00016 id = OCSP_cert_to_id(NULL, cert.cert, issuer.cert); 00017 OCSP_request_add0_id(req, id); 00018 } 00019 } 00020 00021 00022 WvOCSPReq::~WvOCSPReq() 00023 { 00024 if (req) 00025 OCSP_REQUEST_free(req); 00026 00027 wvssl_free(); 00028 } 00029 00030 00031 void WvOCSPReq::encode(WvBuf &buf) 00032 { 00033 BIO *bufbio = BIO_new(BIO_s_mem()); 00034 assert(bufbio); 00035 BUF_MEM *bm; 00036 00037 // there is no reason why the following should fail, except for OOM 00038 assert(wv_i2d_OCSP_REQUEST_bio(bufbio, req) > 0); 00039 00040 BIO_get_mem_ptr(bufbio, &bm); 00041 buf.put(bm->data, bm->length); 00042 BIO_free(bufbio); 00043 } 00044 00045 00046 WvOCSPResp::WvOCSPResp() : 00047 resp(NULL), 00048 bs(NULL), 00049 log("OCSP Response", WvLog::Debug5) 00050 { 00051 wvssl_init(); 00052 } 00053 00054 00055 WvOCSPResp::~WvOCSPResp() 00056 { 00057 if (bs) 00058 OCSP_BASICRESP_free(bs); 00059 00060 if (resp) 00061 OCSP_RESPONSE_free(resp); 00062 00063 wvssl_free(); 00064 } 00065 00066 00067 void WvOCSPResp::decode(WvBuf &encoded) 00068 { 00069 BIO *membuf = BIO_new(BIO_s_mem()); 00070 BIO_write(membuf, encoded.get(encoded.used()), encoded.used()); 00071 00072 resp = d2i_OCSP_RESPONSE_bio(membuf, NULL); 00073 00074 if (resp) 00075 bs = OCSP_response_get1_basic(resp); 00076 else 00077 log("Failed to decode response.\n"); 00078 00079 BIO_free_all(membuf); 00080 } 00081 00082 00083 bool WvOCSPResp::isok() const 00084 { 00085 if (!resp) 00086 return false; 00087 00088 int i = OCSP_response_status(resp); 00089 if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL) 00090 { 00091 log("Status not successful: %s\n", wvssl_errstr()); 00092 return false; 00093 } 00094 00095 return true; 00096 } 00097 00098 00099 bool WvOCSPResp::check_nonce(const WvOCSPReq &req) const 00100 { 00101 if (!bs) 00102 return false; 00103 00104 int i; 00105 if ((i = OCSP_check_nonce(req.req, bs)) <= 0) 00106 { 00107 if (i == -1) 00108 log("No nonce in response\n"); 00109 else 00110 log("Nonce verify error\n"); 00111 00112 return false; 00113 } 00114 00115 return true; 00116 } 00117 00118 00119 bool WvOCSPResp::signedbycert(const WvX509 &cert) const 00120 { 00121 EVP_PKEY *skey = X509_get_pubkey(cert.cert); 00122 int i = OCSP_BASICRESP_verify(bs, skey, 0); 00123 EVP_PKEY_free(skey); 00124 00125 if(i > 0) 00126 return true; 00127 00128 return false; 00129 } 00130 00131 00132 WvX509 WvOCSPResp::get_signing_cert() const 00133 { 00134 if (!bs || !sk_X509_num(bs->certs)) 00135 return WvX509(); 00136 00137 // note: the following bit of code is taken almost verbatim from 00138 // ocsp_vfy.c in OpenSSL 0.9.8. Copyright and attribution should 00139 // properly belong to them 00140 00141 OCSP_RESPID *id = bs->tbsResponseData->responderId; 00142 00143 if (id->type == V_OCSP_RESPID_NAME) 00144 { 00145 X509 *x = X509_find_by_subject(bs->certs, id->value.byName); 00146 if (x) 00147 return WvX509(X509_dup(x)); 00148 } 00149 00150 if (id->value.byKey->length != SHA_DIGEST_LENGTH) return NULL; 00151 unsigned char tmphash[SHA_DIGEST_LENGTH]; 00152 unsigned char *keyhash = id->value.byKey->data; 00153 for (int i = 0; i < sk_X509_num(bs->certs); i++) 00154 { 00155 X509 *x = sk_X509_value(bs->certs, i); 00156 X509_pubkey_digest(x, EVP_sha1(), tmphash, NULL); 00157 if(!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH)) 00158 return WvX509(X509_dup(x)); 00159 } 00160 00161 return WvX509(); 00162 } 00163 00164 00165 WvOCSPResp::Status WvOCSPResp::get_status(const WvX509 &cert, 00166 const WvX509 &issuer) const 00167 { 00168 if (!isok()) 00169 return Error; 00170 00171 if (!cert.isok() && !issuer.isok()) 00172 return Error; 00173 00174 int status, reason; 00175 ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; 00176 00177 OCSP_CERTID *id = OCSP_cert_to_id(NULL, cert.cert, issuer.cert); 00178 assert(id); // only fails in case of OOM 00179 00180 if(!OCSP_resp_find_status(bs, id, &status, &reason, 00181 &rev, &thisupd, &nextupd)) 00182 { 00183 log("OCSP Find Status Error: %s\n", wvssl_errstr()); 00184 OCSP_CERTID_free(id); 00185 return Error; 00186 } 00187 OCSP_CERTID_free(id); 00188 00189 if (!OCSP_check_validity(thisupd, nextupd, OCSP_MAX_VALIDITY_PERIOD, -1)) 00190 { 00191 log("Error checking for OCSP validity: %s\n", wvssl_errstr()); 00192 return Error; 00193 } 00194 00195 if (status == V_OCSP_CERTSTATUS_GOOD) 00196 return Good; 00197 else if (status == V_OCSP_CERTSTATUS_REVOKED) 00198 return Revoked; 00199 00200 log("OCSP cert status is %s, marking as 'Unknown'.\n", 00201 OCSP_cert_status_str(status)); 00202 00203 return Unknown; 00204 } 00205 00206 WvString WvOCSPResp::status_str(WvOCSPResp::Status status) 00207 { 00208 if (status == Good) 00209 return "good"; 00210 else if (status == Error) 00211 return "error"; 00212 else if (status == Revoked) 00213 return "revoked"; 00214 00215 return "unknown"; 00216 }