/** * @file llsecapi.h * @brief Security API for services such as certificate handling * secure local storage, etc. * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLSECAPI_H #define LLSECAPI_H #include <vector> #include <openssl/x509.h> #include <ostream> #ifdef LL_WINDOWS #pragma warning(disable:4250) #endif // LL_WINDOWS // All error handling is via exceptions. #define CERT_SUBJECT_NAME "subject_name" #define CERT_ISSUER_NAME "issuer_name" #define CERT_NAME_CN "commonName" #define CERT_SUBJECT_NAME_STRING "subject_name_string" #define CERT_ISSUER_NAME_STRING "issuer_name_string" #define CERT_SERIAL_NUMBER "serial_number" #define CERT_VALID_FROM "valid_from" #define CERT_VALID_TO "valid_to" #define CERT_SHA1_DIGEST "sha1_digest" #define CERT_MD5_DIGEST "md5_digest" #define CERT_HOSTNAME "hostname" #define CERT_BASIC_CONSTRAINTS "basicConstraints" #define CERT_BASIC_CONSTRAINTS_CA "CA" #define CERT_BASIC_CONSTRAINTS_PATHLEN "pathLen" #define CERT_KEY_USAGE "keyUsage" #define CERT_KU_DIGITAL_SIGNATURE "digitalSignature" #define CERT_KU_NON_REPUDIATION "nonRepudiation" #define CERT_KU_KEY_ENCIPHERMENT "keyEncipherment" #define CERT_KU_DATA_ENCIPHERMENT "dataEncipherment" #define CERT_KU_KEY_AGREEMENT "keyAgreement" #define CERT_KU_CERT_SIGN "certSigning" #define CERT_KU_CRL_SIGN "crlSigning" #define CERT_KU_ENCIPHER_ONLY "encipherOnly" #define CERT_KU_DECIPHER_ONLY "decipherOnly" #define BASIC_SECHANDLER "BASIC_SECHANDLER" #define CERT_VALIDATION_DATE "validation_date" #define CERT_EXTENDED_KEY_USAGE "extendedKeyUsage" #define CERT_EKU_SERVER_AUTH SN_server_auth #define CERT_SUBJECT_KEY_IDENTFIER "subjectKeyIdentifier" #define CERT_AUTHORITY_KEY_IDENTIFIER "authorityKeyIdentifier" #define CERT_AUTHORITY_KEY_IDENTIFIER_ID "authorityKeyIdentifierId" #define CERT_AUTHORITY_KEY_IDENTIFIER_NAME "authorityKeyIdentifierName" #define CERT_AUTHORITY_KEY_IDENTIFIER_SERIAL "authorityKeyIdentifierSerial" // validate the current time lies within // the validation period of the cert #define VALIDATION_POLICY_TIME 1 // validate that the CA, or some cert in the chain // lies within the certificate store #define VALIDATION_POLICY_TRUSTED 2 // validate that the subject name of // the cert contains the passed in hostname // or validates against the hostname #define VALIDATION_POLICY_HOSTNAME 4 // validate that the cert contains the SSL EKU #define VALIDATION_POLICY_SSL_KU 8 // validate that the cert contains the SSL EKU #define VALIDATION_POLICY_CA_KU 16 #define VALIDATION_POLICY_CA_BASIC_CONSTRAINTS 32 // validate that the cert is correct for SSL #define VALIDATION_POLICY_SSL (VALIDATION_POLICY_TIME | \ VALIDATION_POLICY_HOSTNAME | \ VALIDATION_POLICY_TRUSTED | \ VALIDATION_POLICY_SSL_KU | \ VALIDATION_POLICY_CA_BASIC_CONSTRAINTS | \ VALIDATION_POLICY_CA_KU) class LLProtectedDataException { public: LLProtectedDataException(const char *msg) { LL_WARNS("SECAPI") << "Protected Data Error: " << (std::string)msg << LL_ENDL; mMsg = (std::string)msg; } std::string getMessage() { return mMsg; } protected: std::string mMsg; }; // class LLCertificate // parent class providing an interface for certifiate. // LLCertificates are considered unmodifiable // Certificates are pulled out of stores, or created via // factory calls class LLCertificate : public LLThreadSafeRefCount { LOG_CLASS(LLCertificate); public: LLCertificate() {} virtual ~LLCertificate() {} // return a PEM encoded certificate. The encoding // includes the -----BEGIN CERTIFICATE----- and end certificate elements virtual std::string getPem() const=0; // return a DER encoded certificate virtual std::vector<U8> getBinary() const=0; // return an LLSD object containing information about the certificate // such as its name, signature, expiry time, serial number virtual void getLLSD(LLSD& llsd)=0; // return an openSSL X509 struct for the certificate virtual X509* getOpenSSLX509() const=0; }; // class LLCertificateVector // base class for a list of certificates. class LLCertificateVector : public LLThreadSafeRefCount { public: LLCertificateVector() {}; virtual ~LLCertificateVector() {}; // base iterator implementation class, providing // the functionality needed for the iterator class. class iterator_impl : public LLThreadSafeRefCount { public: iterator_impl() {}; virtual ~iterator_impl() {}; virtual void seek(bool incr)=0; virtual LLPointer<iterator_impl> clone() const=0; virtual bool equals(const LLPointer<iterator_impl>& _iter) const=0; virtual LLPointer<LLCertificate> get()=0; }; // iterator class class iterator { public: iterator(LLPointer<iterator_impl> impl) : mImpl(impl) {} iterator() : mImpl(NULL) {} iterator(const iterator& _iter) {mImpl = _iter.mImpl->clone(); } ~iterator() {} iterator& operator++() { if(mImpl.notNull()) mImpl->seek(true); return *this;} iterator& operator--() { if(mImpl.notNull()) mImpl->seek(false); return *this;} iterator operator++(int) { iterator result = *this; if(mImpl.notNull()) mImpl->seek(true); return result;} iterator operator--(int) { iterator result = *this; if(mImpl.notNull()) mImpl->seek(false); return result;} LLPointer<LLCertificate> operator*() { return mImpl->get(); } LLPointer<iterator_impl> mImpl; protected: friend bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs); bool equals(const iterator& _iter) const { return mImpl->equals(_iter.mImpl); } }; // numeric indexer virtual LLPointer<LLCertificate> operator[](int)=0; // Iteration virtual iterator begin()=0; virtual iterator end()=0; // find a cert given params virtual iterator find(const LLSD& params) =0; // return the number of certs in the store virtual int size() const = 0; // append the cert to the store. if a copy of the cert already exists in the store, it is removed first virtual void add(LLPointer<LLCertificate> cert)=0; // insert the cert to the store. if a copy of the cert already exists in the store, it is removed first virtual void insert(iterator location, LLPointer<LLCertificate> cert)=0; // remove a certificate from the store virtual LLPointer<LLCertificate> erase(iterator cert)=0; }; // class LLCertificateChain // Class representing a chain of certificates in order, with the // first element being the child cert. class LLCertificateChain : virtual public LLCertificateVector { public: LLCertificateChain() {} virtual ~LLCertificateChain() {} }; // class LLCertificateStore // represents a store of certificates, typically a store of root CA // certificates. The store can be persisted, and can be used to validate // a cert chain // class LLCertificateStore : virtual public LLCertificateVector { public: LLCertificateStore() {} virtual ~LLCertificateStore() {} // persist the store virtual void save()=0; // return the store id virtual std::string storeId() const=0; // validate a certificate chain given the params. // Will throw exceptions on error virtual void validate(int validation_policy, LLPointer<LLCertificateChain> cert_chain, const LLSD& validation_params) =0; }; inline bool operator==(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs) { return _lhs.equals(_rhs); } inline bool operator!=(const LLCertificateVector::iterator& _lhs, const LLCertificateVector::iterator& _rhs) { return !(_lhs == _rhs); } #define CRED_IDENTIFIER_TYPE_ACCOUNT "account" #define CRED_IDENTIFIER_TYPE_AGENT "agent" #define CRED_AUTHENTICATOR_TYPE_CLEAR "clear" #define CRED_AUTHENTICATOR_TYPE_HASH "hash" // // LLCredential - interface for credentials providing the following functionality: // * Persistence of credential information based on grid (for saving username/password) // * Serialization to an OGP identifier/authenticator pair // class LLCredential : public LLThreadSafeRefCount { public: LLCredential() {} LLCredential(const std::string& grid) { mGrid = grid; mIdentifier = LLSD::emptyMap(); mAuthenticator = LLSD::emptyMap(); } virtual ~LLCredential() {} virtual void setCredentialData(const LLSD& identifier, const LLSD& authenticator) { mIdentifier = identifier; mAuthenticator = authenticator; } virtual LLSD getIdentifier() { return mIdentifier; } virtual void identifierType(std::string& idType); virtual LLSD getAuthenticator() { return mAuthenticator; } virtual void authenticatorType(std::string& authType); virtual LLSD getLoginParams(); virtual std::string getGrid() { return mGrid; } virtual void clearAuthenticator() { mAuthenticator = LLSD(); } virtual std::string userID() const { return std::string("unknown");} virtual std::string asString() const { return std::string("unknown");} operator std::string() const { return asString(); } protected: LLSD mIdentifier; LLSD mAuthenticator; std::string mGrid; }; std::ostream& operator <<(std::ostream& s, const LLCredential& cred); // All error handling is via exceptions. class LLCertException { public: LLCertException(LLPointer<LLCertificate> cert, const char* msg) { mCert = cert; LL_WARNS("SECAPI") << "Certificate Error: " << (std::string)msg << LL_ENDL; mMsg = (std::string)msg; } LLPointer<LLCertificate> getCert() { return mCert; } std::string getMessage() { return mMsg; } protected: LLPointer<LLCertificate> mCert; std::string mMsg; }; class LLInvalidCertificate : public LLCertException { public: LLInvalidCertificate(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalid") { } protected: }; class LLCertValidationTrustException : public LLCertException { public: LLCertValidationTrustException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertUntrusted") { } protected: }; class LLCertValidationHostnameException : public LLCertException { public: LLCertValidationHostnameException(std::string hostname, LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidHostname") { mHostname = hostname; } std::string getHostname() { return mHostname; } protected: std::string mHostname; }; class LLCertValidationExpirationException : public LLCertException { public: LLCertValidationExpirationException(LLPointer<LLCertificate> cert, LLDate current_time) : LLCertException(cert, "CertExpired") { mTime = current_time; } LLDate GetTime() { return mTime; } protected: LLDate mTime; }; class LLCertKeyUsageValidationException : public LLCertException { public: LLCertKeyUsageValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertKeyUsage") { } protected: }; class LLCertBasicConstraintsValidationException : public LLCertException { public: LLCertBasicConstraintsValidationException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertBasicConstraints") { } protected: }; class LLCertValidationInvalidSignatureException : public LLCertException { public: LLCertValidationInvalidSignatureException(LLPointer<LLCertificate> cert) : LLCertException(cert, "CertInvalidSignature") { } protected: }; // LLSecAPIHandler Class // Interface handler class for the various security storage handlers. class LLSecAPIHandler : public LLThreadSafeRefCount { public: LLSecAPIHandler() {} virtual ~LLSecAPIHandler() {} // initialize the SecAPIHandler virtual void init() {}; // instantiate a certificate from a pem string virtual LLPointer<LLCertificate> getCertificate(const std::string& pem_cert)=0; // instiate a certificate from an openssl X509 structure virtual LLPointer<LLCertificate> getCertificate(X509* openssl_cert)=0; // instantiate a chain from an X509_STORE_CTX virtual LLPointer<LLCertificateChain> getCertificateChain(const X509_STORE_CTX* chain)=0; // instantiate a cert store given it's id. if a persisted version // exists, it'll be loaded. If not, one will be created (but not // persisted) virtual LLPointer<LLCertificateStore> getCertificateStore(const std::string& store_id)=0; // persist data in a protected store virtual void setProtectedData(const std::string& data_type, const std::string& data_id, const LLSD& data)=0; // retrieve protected data virtual LLSD getProtectedData(const std::string& data_type, const std::string& data_id)=0; // delete a protected data item from the store virtual void deleteProtectedData(const std::string& data_type, const std::string& data_id)=0; virtual LLPointer<LLCredential> createCredential(const std::string& grid, const LLSD& identifier, const LLSD& authenticator)=0; virtual LLPointer<LLCredential> loadCredential(const std::string& grid)=0; virtual void saveCredential(LLPointer<LLCredential> cred, bool save_authenticator)=0; virtual void deleteCredential(LLPointer<LLCredential> cred)=0; }; void initializeSecHandler(); // retrieve a security api depending on the api type LLPointer<LLSecAPIHandler> getSecHandler(const std::string& handler_type); void registerSecHandler(const std::string& handler_type, LLPointer<LLSecAPIHandler>& handler); extern LLPointer<LLSecAPIHandler> gSecAPIHandler; int secapiSSLCertVerifyCallback(X509_STORE_CTX *ctx, void *param); #endif // LL_SECAPI_H