bool _verify_signature(LLPointer<LLCertificate> parent, LLPointer<LLCertificate> child) { bool verify_result = FALSE; LLSD cert1, cert2; parent->getLLSD(cert1); child->getLLSD(cert2); X509 *signing_cert = parent->getOpenSSLX509(); X509 *child_cert = child->getOpenSSLX509(); if((signing_cert != NULL) && (child_cert != NULL)) { EVP_PKEY *pkey = X509_get_pubkey(signing_cert); if(pkey) { int verify_code = X509_verify(child_cert, pkey); verify_result = ( verify_code > 0); EVP_PKEY_free(pkey); } else { LL_WARNS("SECAPI") << "Could not validate the cert chain signature, as the public key of the signing cert could not be retrieved" << LL_ENDL; } } else { LL_WARNS("SECAPI") << "Signature verification failed as there are no certs in the chain" << LL_ENDL; } if(child_cert) { X509_free(child_cert); } if(signing_cert) { X509_free(signing_cert); } return verify_result; }
// // LLBasicCertificateChain // This class represents a chain of certs, each cert being signed by the next cert // in the chain. Certs must be properly signed by the parent LLBasicCertificateChain::LLBasicCertificateChain(const X509_STORE_CTX* store) { // we're passed in a context, which contains a cert, and a blob of untrusted // certificates which compose the chain. if((store == NULL) || (store->cert == NULL)) { LL_WARNS("SECAPI") << "An invalid store context was passed in when trying to create a certificate chain" << LL_ENDL; return; } // grab the child cert LLPointer<LLCertificate> current = new LLBasicCertificate(store->cert); add(current); if(store->untrusted != NULL) { // if there are other certs in the chain, we build up a vector // of untrusted certs so we can search for the parents of each // consecutive cert. LLBasicCertificateVector untrusted_certs; for(int i = 0; i < sk_X509_num(store->untrusted); i++) { LLPointer<LLCertificate> cert = new LLBasicCertificate(sk_X509_value(store->untrusted, i)); untrusted_certs.add(cert); } while(untrusted_certs.size() > 0) { LLSD find_data = LLSD::emptyMap(); LLSD cert_data; current->getLLSD(cert_data); // we simply build the chain via subject/issuer name as the // client should not have passed in multiple CA's with the same // subject name. If they did, it'll come out in the wash during // validation. find_data[CERT_SUBJECT_NAME_STRING] = cert_data[CERT_ISSUER_NAME_STRING]; LLBasicCertificateVector::iterator issuer = untrusted_certs.find(find_data); if (issuer != untrusted_certs.end()) { current = untrusted_certs.erase(issuer); add(current); } else { break; } } } }
// Insert a certificate into the store. If the certificate already // exists in the store, nothing is done. void LLBasicCertificateVector::insert(iterator _iter, LLPointer<LLCertificate> cert) { LLSD cert_info; cert->getLLSD(cert_info); if (cert_info.isMap() && cert_info.has(CERT_SHA1_DIGEST)) { LLSD existing_cert_info = LLSD::emptyMap(); existing_cert_info[CERT_MD5_DIGEST] = cert_info[CERT_MD5_DIGEST]; if(find(existing_cert_info) == end()) { BasicIteratorImpl *basic_iter = dynamic_cast<BasicIteratorImpl*>(_iter.mImpl.get()); llassert(basic_iter); if (basic_iter) { mCerts.insert(basic_iter->mIter, cert); } } } }
void _validateCert(int validation_policy, LLPointer<LLCertificate> cert, const LLSD& validation_params, int depth) { LLSD current_cert_info; cert->getLLSD(current_cert_info); // check basic properties exist in the cert if(!current_cert_info.has(CERT_SUBJECT_NAME) || !current_cert_info.has(CERT_SUBJECT_NAME_STRING)) { throw LLCertException(cert, "Cert doesn't have a Subject Name"); } if(!current_cert_info.has(CERT_ISSUER_NAME_STRING)) { throw LLCertException(cert, "Cert doesn't have an Issuer Name"); } // check basic properties exist in the cert if(!current_cert_info.has(CERT_VALID_FROM) || !current_cert_info.has(CERT_VALID_TO)) { throw LLCertException(cert, "Cert doesn't have an expiration period"); } if (!current_cert_info.has(CERT_SHA1_DIGEST)) { throw LLCertException(cert, "No SHA1 digest"); } if (validation_policy & VALIDATION_POLICY_TIME) { LLDate validation_date(time(NULL)); if(validation_params.has(CERT_VALIDATION_DATE)) { validation_date = validation_params[CERT_VALIDATION_DATE]; } if((validation_date < current_cert_info[CERT_VALID_FROM].asDate()) || (validation_date > current_cert_info[CERT_VALID_TO].asDate())) { throw LLCertValidationExpirationException(cert, validation_date); } } if (validation_policy & VALIDATION_POLICY_SSL_KU) { if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() && (!(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], LLSD((std::string)CERT_KU_DIGITAL_SIGNATURE))) || !(_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], LLSD((std::string)CERT_KU_KEY_ENCIPHERMENT))))) { throw LLCertKeyUsageValidationException(cert); } // only validate EKU if the cert has it if(current_cert_info.has(CERT_EXTENDED_KEY_USAGE) && current_cert_info[CERT_EXTENDED_KEY_USAGE].isArray() && (!_LLSDArrayIncludesValue(current_cert_info[CERT_EXTENDED_KEY_USAGE], LLSD((std::string)CERT_EKU_SERVER_AUTH)))) { throw LLCertKeyUsageValidationException(cert); } } if (validation_policy & VALIDATION_POLICY_CA_KU) { if (current_cert_info.has(CERT_KEY_USAGE) && current_cert_info[CERT_KEY_USAGE].isArray() && (!_LLSDArrayIncludesValue(current_cert_info[CERT_KEY_USAGE], (std::string)CERT_KU_CERT_SIGN))) { throw LLCertKeyUsageValidationException(cert); } } // validate basic constraints if ((validation_policy & VALIDATION_POLICY_CA_BASIC_CONSTRAINTS) && current_cert_info.has(CERT_BASIC_CONSTRAINTS) && current_cert_info[CERT_BASIC_CONSTRAINTS].isMap()) { if(!current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_CA) || !current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_CA]) { throw LLCertBasicConstraintsValidationException(cert); } if (current_cert_info[CERT_BASIC_CONSTRAINTS].has(CERT_BASIC_CONSTRAINTS_PATHLEN) && ((current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger() != 0) && (depth > current_cert_info[CERT_BASIC_CONSTRAINTS][CERT_BASIC_CONSTRAINTS_PATHLEN].asInteger()))) { throw LLCertBasicConstraintsValidationException(cert); } } }