• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

OCSPStapling.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   @section license License
00004 
00005   Licensed to the Apache Software Foundation (ASF) under one
00006   or more contributor license agreements.  See the NOTICE file
00007   distributed with this work for additional information
00008   regarding copyright ownership.  The ASF licenses this file
00009   to you under the Apache License, Version 2.0 (the
00010   "License"); you may not use this file except in compliance
00011   with the License.  You may obtain a copy of the License at
00012 
00013       http://www.apache.org/licenses/LICENSE-2.0
00014 
00015   Unless required by applicable law or agreed to in writing, software
00016   distributed under the License is distributed on an "AS IS" BASIS,
00017   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00018   See the License for the specific language governing permissions and
00019   limitations under the License.
00020  */
00021 
00022 #include <openssl/ocsp.h>
00023 #include "P_OCSPStapling.h"
00024 #include "P_Net.h"
00025 #include "P_SSLConfig.h"
00026 
00027 #ifdef HAVE_OPENSSL_OCSP_STAPLING
00028 
00029 // Maxiumum OCSP stapling response size.
00030 // This should be the response for a single certificate and will typically include the responder certificate chain,
00031 // so 10K should be more than enough.
00032 #define MAX_STAPLING_DER 10240
00033 
00034 // Cached info stored in SSL_CTX ex_info
00035 struct certinfo
00036 {
00037   unsigned char idx[20];  // Index in session cache SHA1 hash of certificate
00038   OCSP_CERTID *cid; // Certificate ID for OCSP requests or NULL if ID cannot be determined
00039   char *uri;  // Responder details
00040   ink_mutex stapling_mutex;
00041   unsigned char resp_der[MAX_STAPLING_DER];
00042   unsigned int resp_derlen;
00043   bool is_expire;
00044   time_t expire_time;
00045 };
00046 
00047 void certinfo_free(void * /*parent*/, void *ptr, CRYPTO_EX_DATA * /*ad*/,
00048     int /*idx*/, long /*argl*/, void * /*argp*/)
00049 {
00050   certinfo *cinf = (certinfo *)ptr;
00051 
00052   if (!cinf)
00053     return;
00054   if (cinf->uri)
00055     OPENSSL_free(cinf->uri);
00056   ink_mutex_destroy(&cinf->stapling_mutex);
00057   OPENSSL_free(cinf);
00058 }
00059 
00060 static int ssl_stapling_index = -1;
00061 
00062 void ssl_stapling_ex_init(void)
00063 {
00064   if (ssl_stapling_index != -1)
00065     return;
00066   ssl_stapling_index = SSL_CTX_get_ex_new_index(0, 0, 0, 0, certinfo_free);
00067 }
00068 
00069 static X509 *
00070 stapling_get_issuer(SSL_CTX *ssl_ctx, X509 *x)
00071 {
00072   X509 *issuer = NULL;
00073   int i;
00074   X509_STORE *st = SSL_CTX_get_cert_store(ssl_ctx);
00075   X509_STORE_CTX inctx;
00076   STACK_OF(X509) *extra_certs = NULL;
00077 
00078 #ifdef SSL_CTX_get_extra_chain_certs
00079   SSL_CTX_get_extra_chain_certs(ssl_ctx, &extra_certs);
00080 #else
00081   extra_certs = ssl_ctx->extra_certs;
00082 #endif
00083 
00084   if (sk_X509_num(extra_certs) == 0)
00085     return NULL;
00086 
00087   for (i = 0; i < sk_X509_num(extra_certs); i++) {
00088     issuer = sk_X509_value(extra_certs, i);
00089     if (X509_check_issued(issuer, x) == X509_V_OK) {
00090       CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509);
00091       return issuer;
00092     }
00093   }
00094 
00095   if (!X509_STORE_CTX_init(&inctx, st, NULL, NULL))
00096     return NULL;
00097   if (X509_STORE_CTX_get1_issuer(&issuer, &inctx, x) <= 0)
00098     issuer = NULL;
00099   X509_STORE_CTX_cleanup(&inctx);
00100 
00101   return issuer;
00102 }
00103 
00104 bool
00105 ssl_stapling_init_cert(SSL_CTX *ctx, const char *certfile)
00106 {
00107   certinfo *cinf;
00108   X509 *cert = NULL;
00109   X509 *issuer = NULL;
00110   STACK_OF(OPENSSL_STRING) *aia = NULL;
00111   BIO *bio = BIO_new_file(certfile, "r");
00112 
00113   cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
00114   if (!cert) {
00115     Debug("ssl", "can not read cert from certfile %s!", certfile);
00116     return false;
00117   }
00118 
00119   cinf  = (certinfo *)SSL_CTX_get_ex_data(ctx, ssl_stapling_index);
00120   if (cinf) {
00121     Debug("ssl", "certificate already initialized!");
00122     return false;
00123   }
00124 
00125   cinf = (certinfo *)OPENSSL_malloc(sizeof(certinfo));
00126   if (!cinf) {
00127     Debug("ssl", "error allocating memory!");
00128     return false;
00129   }
00130 
00131   // Initialize certinfo
00132   cinf->cid = NULL;
00133   cinf->uri = NULL;
00134   cinf->resp_derlen = 0;
00135   ink_mutex_init(&cinf->stapling_mutex, "stapling_mutex");
00136   cinf->is_expire = true;
00137   cinf->expire_time = 0;
00138 
00139   SSL_CTX_set_ex_data(ctx, ssl_stapling_index, cinf);
00140 
00141   issuer = stapling_get_issuer(ctx, cert);
00142   if (issuer == NULL) {
00143         Debug("ssl", "can not get issuer certificate!");
00144     return false;
00145   }
00146 
00147   cinf->cid = OCSP_cert_to_id(NULL, cert, issuer);
00148   X509_free(issuer);
00149   if (!cinf->cid)
00150     return false;
00151   X509_digest(cert, EVP_sha1(), cinf->idx, NULL);
00152 
00153   aia = X509_get1_ocsp(cert);
00154   if (aia)
00155     cinf->uri = sk_OPENSSL_STRING_pop(aia);
00156   if (!cinf->uri) {
00157         Debug("ssl", "no responder URI");
00158   }
00159   if (aia)
00160     X509_email_free(aia);
00161 
00162   Debug("ssl", "success to init certinfo into SSL_CTX: %p", ctx);
00163   return true;
00164 }
00165 
00166 static certinfo *
00167 stapling_get_cert_info(SSL_CTX *ctx)
00168 {
00169   certinfo *cinf;
00170 
00171   cinf = (certinfo *)SSL_CTX_get_ex_data(ctx, ssl_stapling_index);
00172   if (cinf && cinf->cid)
00173     return cinf;
00174 
00175   return NULL;
00176 }
00177 
00178 static bool
00179 stapling_cache_response(OCSP_RESPONSE *rsp, certinfo *cinf)
00180 {
00181   unsigned char resp_der[MAX_STAPLING_DER];
00182   unsigned char *p;
00183   unsigned int resp_derlen;
00184 
00185   p = resp_der;
00186   resp_derlen = i2d_OCSP_RESPONSE(rsp, &p);
00187 
00188   if (resp_derlen == 0) {
00189     Error("stapling_cache_response: can not encode OCSP stapling response");
00190     return false;
00191   }
00192 
00193   if (resp_derlen > MAX_STAPLING_DER) {
00194     Error("stapling_cache_response: OCSP stapling response too big (%u bytes)", resp_derlen);
00195     return false;
00196   }
00197 
00198   ink_mutex_acquire(&cinf->stapling_mutex);
00199   memcpy(cinf->resp_der, resp_der, resp_derlen);
00200   cinf->resp_derlen = resp_derlen;
00201   cinf->is_expire = false;
00202   cinf->expire_time = time(NULL) + SSLConfigParams::ssl_ocsp_cache_timeout;
00203   ink_mutex_release(&cinf->stapling_mutex);
00204 
00205   Debug("ssl", "stapling_cache_response: success to cache response");
00206   return true;
00207 }
00208 
00209 static int
00210 stapling_check_response(certinfo *cinf, OCSP_RESPONSE *rsp)
00211 {
00212   int status, reason;
00213   OCSP_BASICRESP *bs = NULL;
00214   ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
00215   int response_status = OCSP_response_status(rsp);
00216 
00217   // Check to see if response is an error.
00218   // If so we automatically accept it because it would have expired from the cache if it was time to retry.
00219   if (response_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
00220     return SSL_TLSEXT_ERR_NOACK;
00221   }
00222 
00223   bs = OCSP_response_get1_basic(rsp);
00224   if (bs == NULL) {
00225     // If we can't parse response just pass it back to client
00226     Error("stapling_check_response: can not parsing response");
00227     return SSL_TLSEXT_ERR_OK;
00228   }
00229   if (!OCSP_resp_find_status(bs, cinf->cid, &status, &reason, &rev,
00230         &thisupd, &nextupd)) {
00231     // If ID not present just pass it back to client
00232     Error("stapling_check_response: certificate ID not present in response");
00233   } else {
00234     OCSP_check_validity(thisupd, nextupd, 300, -1);
00235   }
00236   OCSP_BASICRESP_free(bs);
00237 
00238   return SSL_TLSEXT_ERR_OK;
00239 }
00240 
00241 static OCSP_RESPONSE *
00242 query_responder(BIO *b, char *host, char *path, OCSP_REQUEST *req, int req_timeout)
00243 {
00244   ink_hrtime start, end;
00245   OCSP_RESPONSE *resp = NULL;
00246   OCSP_REQ_CTX *ctx;
00247   int rv;
00248 
00249   start = ink_get_hrtime();
00250   end = ink_hrtime_add(start, ink_hrtime_from_sec(req_timeout));
00251 
00252   ctx = OCSP_sendreq_new(b, path, NULL, -1);
00253   OCSP_REQ_CTX_add1_header(ctx, "Host", host);
00254   OCSP_REQ_CTX_set1_req(ctx, req);
00255 
00256   do {
00257     rv = OCSP_sendreq_nbio(&resp, ctx);
00258     ink_hrtime_sleep(HRTIME_MSECONDS(1));
00259   } while ((rv == -1) && BIO_should_retry(b) && (ink_get_hrtime() < end));
00260 
00261   OCSP_REQ_CTX_free(ctx);
00262 
00263   if (rv)
00264     return resp;
00265 
00266   return NULL;
00267 }
00268 
00269 static OCSP_RESPONSE *
00270 process_responder(OCSP_REQUEST *req,
00271     char *host, char *path, char *port,
00272     int req_timeout)
00273 {
00274   BIO *cbio = NULL;
00275   OCSP_RESPONSE *resp = NULL;
00276   cbio = BIO_new_connect(host);
00277   if (!cbio) {
00278     goto end;
00279   }
00280   if (port) BIO_set_conn_port(cbio, port);
00281 
00282   BIO_set_nbio(cbio, 1);
00283   if (BIO_do_connect(cbio) <= 0 && !BIO_should_retry(cbio)) {
00284     Debug("ssl", "process_responder: fail to connect to OCSP respond server");
00285     goto end;
00286   }
00287   resp = query_responder(cbio, host, path, req, req_timeout);
00288 
00289 end:
00290   if (cbio)
00291     BIO_free_all(cbio);
00292   return resp;
00293 }
00294 
00295 static bool
00296 stapling_refresh_response(certinfo *cinf, OCSP_RESPONSE **prsp)
00297 {
00298   bool rv = true;
00299   OCSP_REQUEST *req = NULL;
00300   OCSP_CERTID *id = NULL;
00301   char *host, *path, *port;
00302   int ssl_flag = 0;
00303   int req_timeout = -1;
00304 
00305   Debug("ssl", "stapling_refresh_response: querying responder");
00306   *prsp = NULL;
00307 
00308   if (!OCSP_parse_url(cinf->uri, &host, &port, &path, &ssl_flag)) {
00309     goto err;
00310   }
00311 
00312   req = OCSP_REQUEST_new();
00313   if (!req)
00314     goto err;
00315   id = OCSP_CERTID_dup(cinf->cid);
00316   if (!id)
00317     goto err;
00318   if (!OCSP_request_add0_id(req, id))
00319     goto err;
00320 
00321   req_timeout = SSLConfigParams::ssl_ocsp_request_timeout;
00322   *prsp = process_responder(req, host, path, port, req_timeout);
00323 
00324   if (*prsp == NULL) {
00325     goto done;
00326   }
00327 
00328   if (OCSP_response_status(*prsp) == OCSP_RESPONSE_STATUS_SUCCESSFUL) {
00329     Debug("ssl", "stapling_refresh_response: query response received");
00330     stapling_check_response(cinf, *prsp);
00331   } else {
00332     Error("stapling_refresh_response: responder error");
00333   }
00334 
00335   if (!stapling_cache_response(*prsp, cinf)) {
00336     Error("stapling_refresh_response: can not cache response");
00337   } else {
00338     Debug("ssl", "stapling_refresh_response: success to refresh response");
00339   }
00340 
00341 done:
00342   if (req)
00343     OCSP_REQUEST_free(req);
00344   if (*prsp)
00345     OCSP_RESPONSE_free(*prsp);
00346   return rv;
00347 
00348 err:
00349   rv = false;
00350   Debug("ssl", "stapling_refresh_response: fail to refresh response");
00351   goto done;
00352 }
00353 
00354 void
00355 ocsp_update()
00356 {
00357   SSL_CTX *ctx;
00358   certinfo *cinf = NULL;
00359   OCSP_RESPONSE *resp = NULL;
00360   time_t current_time;
00361 
00362   SSLCertificateConfig::scoped_config certLookup;
00363   const unsigned ctxCount = certLookup->count();
00364 
00365   for (unsigned i = 0; i < ctxCount; i++) {
00366     ctx = certLookup->get(i);
00367     cinf = stapling_get_cert_info(ctx);
00368     if (cinf) {
00369       ink_mutex_acquire(&cinf->stapling_mutex);
00370       current_time = time(NULL);
00371       if (cinf->resp_derlen == 0 || cinf->is_expire || cinf->expire_time < current_time) {
00372         ink_mutex_release(&cinf->stapling_mutex);
00373         if (stapling_refresh_response(cinf, &resp)) {
00374           Note("Success to refresh OCSP response for 1 certificate.");
00375         } else {
00376           Note("Fail to refresh OCSP response for 1 certificate.");
00377         }
00378       } else {
00379         ink_mutex_release(&cinf->stapling_mutex);
00380       }
00381     }
00382   }
00383 }
00384 
00385 // RFC 6066 Section-8: Certificate Status Request
00386 int
00387 ssl_callback_ocsp_stapling(SSL *ssl)
00388 {
00389   certinfo *cinf = NULL;
00390   time_t current_time;
00391 
00392   cinf = stapling_get_cert_info(ssl->ctx);
00393   if (cinf == NULL) {
00394     Debug("ssl", "ssl_callback_ocsp_stapling: fail to get certificate information");
00395     return SSL_TLSEXT_ERR_NOACK;
00396   }
00397 
00398   ink_mutex_acquire(&cinf->stapling_mutex);
00399   current_time = time(NULL);
00400   if (cinf->resp_derlen == 0 || cinf->is_expire || cinf->expire_time < current_time) {
00401     ink_mutex_release(&cinf->stapling_mutex);
00402     Debug("ssl", "ssl_callback_ocsp_stapling: fail to get certificate status");
00403     return SSL_TLSEXT_ERR_NOACK;
00404   } else {
00405     unsigned char *p = (unsigned char *)OPENSSL_malloc(cinf->resp_derlen);
00406     unsigned int len = cinf->resp_derlen;
00407     memcpy(p, cinf->resp_der, cinf->resp_derlen);
00408     ink_mutex_release(&cinf->stapling_mutex);
00409     SSL_set_tlsext_status_ocsp_resp(ssl, p, len);
00410     Debug("ssl", "ssl_callback_ocsp_stapling: success to get certificate status");
00411     return SSL_TLSEXT_ERR_OK;
00412   }
00413 }
00414 
00415 #endif /* HAVE_OPENSSL_OCSP_STAPLING */

Generated by  doxygen 1.7.1