00001 #include "wvocsp.h"
00002 #include "wvsslhacks.h"
00003
00004 static const int OCSP_MAX_VALIDITY_PERIOD = (5 * 60);
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
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
00138
00139
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);
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 }