• 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 #include "P_SSLUtils.h"
00027 
00028 #ifdef HAVE_OPENSSL_OCSP_STAPLING
00029 
00030 // Maxiumum OCSP stapling response size.
00031 // This should be the response for a single certificate and will typically include the responder certificate chain,
00032 // so 10K should be more than enough.
00033 #define MAX_STAPLING_DER 10240
00034 
00035 // Cached info stored in SSL_CTX ex_info
00036 struct certinfo
00037 {
00038   unsigned char idx[20];  // Index in session cache SHA1 hash of certificate
00039   OCSP_CERTID *cid; // Certificate ID for OCSP requests or NULL if ID cannot be determined
00040   char *uri;  // Responder details
00041   ink_mutex stapling_mutex;
00042   unsigned char resp_der[MAX_STAPLING_DER];
00043   unsigned int resp_derlen;
00044   bool is_expire;
00045   time_t expire_time;
00046 };
00047 
00048 void certinfo_free(void * /*parent*/, void *ptr, CRYPTO_EX_DATA * /*ad*/,
00049     int /*idx*/, long /*argl*/, void * /*argp*/)
00050 {
00051   certinfo *cinf = (certinfo *)ptr;
00052 
00053   if (!cinf)
00054     return;
00055   if (cinf->uri)
00056     OPENSSL_free(cinf->uri);
00057   ink_mutex_destroy(&cinf->stapling_mutex);
00058   OPENSSL_free(cinf);
00059 }
00060 
00061 static int ssl_stapling_index = -1;
00062 
00063 void ssl_stapling_ex_init(void)
00064 {
00065   if (ssl_stapling_index != -1)
00066     return;
00067   ssl_stapling_index = SSL_CTX_get_ex_new_index(0, 0, 0, 0, certinfo_free);
00068 }
00069 
00070 static X509 *
00071 stapling_get_issuer(SSL_CTX *ssl_ctx, X509 *x)
00072 {
00073   X509 *issuer = NULL;
00074   int i;
00075   X509_STORE *st = SSL_CTX_get_cert_store(ssl_ctx);
00076   X509_STORE_CTX inctx;
00077   STACK_OF(X509) *extra_certs = NULL;
00078 
00079 #ifdef SSL_CTX_get_extra_chain_certs
00080   SSL_CTX_get_extra_chain_certs(ssl_ctx, &extra_certs);
00081 #else
00082   extra_certs = ssl_ctx->extra_certs;
00083 #endif
00084 
00085   if (sk_X509_num(extra_certs) == 0)
00086     return NULL;
00087 
00088   for (i = 0; i < sk_X509_num(extra_certs); i++) {
00089     issuer = sk_X509_value(extra_certs, i);
00090     if (X509_check_issued(issuer, x) == X509_V_OK) {
00091       CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509);
00092       return issuer;
00093     }
00094   }
00095 
00096   if (!X509_STORE_CTX_init(&inctx, st, NULL, NULL))
00097     return NULL;
00098   if (X509_STORE_CTX_get1_issuer(&issuer, &inctx, x) <= 0)
00099     issuer = NULL;
00100   X509_STORE_CTX_cleanup(&inctx);
00101 
00102   return issuer;
00103 }
00104 
00105 bool
00106 ssl_stapling_init_cert(SSL_CTX *ctx, const char *certfile)
00107 {
00108   certinfo *cinf;
00109   scoped_X509 cert;
00110   scoped_X509 issuer;
00111   STACK_OF(OPENSSL_STRING) *aia = NULL;
00112   scoped_BIO bio(BIO_new_file(certfile, "r"));
00113 
00114   cert = PEM_read_bio_X509_AUX(bio.get(), NULL, NULL, NULL);
00115   if (!cert) {
00116     Debug("ssl", "can not read cert from certfile %s!", certfile);
00117     return false;
00118   }
00119 
00120   cinf  = (certinfo *)SSL_CTX_get_ex_data(ctx, ssl_stapling_index);
00121   if (cinf) {
00122     Debug("ssl", "certificate already initialized!");
00123     return false;
00124   }
00125 
00126   cinf = (certinfo *)OPENSSL_malloc(sizeof(certinfo));
00127   if (!cinf) {
00128     Debug("ssl", "error allocating memory!");
00129     return false;
00130   }
00131 
00132   // Initialize certinfo
00133   cinf->cid = NULL;
00134   cinf->uri = NULL;
00135   cinf->resp_derlen = 0;
00136   ink_mutex_init(&cinf->stapling_mutex, "stapling_mutex");
00137   cinf->is_expire = true;
00138   cinf->expire_time = 0;
00139 
00140   SSL_CTX_set_ex_data(ctx, ssl_stapling_index, cinf);
00141 
00142   issuer = stapling_get_issuer(ctx, cert);
00143   if (issuer == NULL) {
00144         Debug("ssl", "can not get issuer certificate!");
00145     return false;
00146   }
00147 
00148   cinf->cid = OCSP_cert_to_id(NULL, cert, 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