//////////////////////////////////////////////////////////////////////////////// // Copyright 2017 Google LLC. // // This software is licensed under the terms defined in the Widevine Master // License Agreement. For a copy of this agreement, please contact // widevine-licensing@google.com. //////////////////////////////////////////////////////////////////////////////// // // Description: // X.509 certificate classes used by the license server SDK. #ifndef COMMON_X509_CERT_H_ #define COMMON_X509_CERT_H_ #include #include #include #include #include #include "base/macros.h" #include "base/thread_annotations.h" #include "absl/synchronization/mutex.h" #include "openssl/pem.h" #include "openssl/x509.h" #include "openssl/x509v3.h" #include "common/status.h" #include "common/openssl_util.h" #include "common/rsa_key.h" namespace widevine { // NOTE: All util::Status codes are in the canonical error space. // Class which holds a single X.509 certificates. class X509Cert { public: // Load the certificate from an openssl X509 certificate instance. static std::unique_ptr FromOpenSslCert(ScopedX509 openssl_cert_); X509Cert(); virtual ~X509Cert(); // Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is // a PEM-encoded certificate. util::Status LoadPem(const std::string& pem_cert); // Load an X.509 certificate. Takes a single parameter, |pem_cert|, which is // a DER-encoded certificate. util::Status LoadDer(const std::string& der_cert); // Return a std::string containing the PEM-encoded certificate. std::string GetPem() const; // Returns certificate RSA public key. nullptr if not found, or if key type // is not RSA. std::unique_ptr GetRsaPublicKey() const; // Returns the internal OpenSSL X509 certificate. const X509* openssl_cert() const { return openssl_cert_; } // Returns the certificate subject name. const std::string& GetSubjectName(); // Returns a field within the certificate subject name, or an empty std::string // if the field is not found. std::string GetSubjectNameField(const std::string& field); // Returns the certificate serial number, binary encoded, or an empty std::string // if an error occurs. std::string GetSerialNumber() const; // Gets the start of the validity period for the certificate in seconds // since the epoch. |valid_start_seconds| must not be null. Returns true on // success, false otherwise. bool GetNotBeforeSeconds(int64_t* valid_start_seconds) const; // Gets the end of the validity period for the certificate in seconds // since the epoch. |valid_end_seconds| must not be null. Returns true on // success, false otherwise. bool GetNotAfterSeconds(int64_t* valid_end_seconds) const; // Returns true if the certificate is a CA (root or intermediate) certificate. bool IsCaCertificate() const; // Gets the value of an X.509 V3 extension encoded as a boolean. |oid| is the // object identifier sequence for the extension, and |value| is a pointer to // an integer which will contain the extension value upon successful return. // Returns true if successful, or false otherwise. bool GetV3BooleanExtension(const std::string& oid, bool* value) const; private: explicit X509Cert(X509* openssl_cert); util::Status Asn1TimeToEpochSeconds(const ASN1_TIME* asn1_time, int64_t* epoch_seconds) const; X509* openssl_cert_; std::string subject_name_; friend class X509CertChain; DISALLOW_COPY_AND_ASSIGN(X509Cert); }; // Class which holds a chain of X.509 certificates. class X509CertChain { public: X509CertChain() {} virtual ~X509CertChain(); // Loads a chain of PEM-encoded X.509 certificates. Takes a single parameter, // |pem_cert_chain|, which is the concatenation of a number of PEM X.509 // certificates, beginning with the leaf certificate, and ending with the // certificate signed by the root CA. util::Status LoadPem(const std::string& pem_cert_chain); // Loads a chain of DER-encoded PKCS#7 certificates. Takes a single parameter, // |pk7_cert_chain|, which is a DER-encoded PKCS#7 X.509 certificate // container. util::Status LoadPkcs7(const std::string& pk7_cert_chain); // Writes the |cert_chain_| to a DER-encoded PKCS#7 X.509 cryptographic // message. The final message does not include signed data. std::string GetPkcs7(); // Returns the number of certificates in the chain. size_t GetNumCerts() const { return cert_chain_.size(); } // Returns the X509Cert at the specified chain index (0 start). Returns // NULL if cert_index is out of range. The X509CertChain retains ownwership // of the object returned. X509Cert* GetCert(size_t cert_index) const; private: void Reset(); std::vector cert_chain_; DISALLOW_COPY_AND_ASSIGN(X509CertChain); }; // CA class which holds the root CA cert, and verifies certificate chains. class X509CA { public: // New object assumes ownership of |ca_cert|. explicit X509CA(X509Cert* ca_cert); virtual ~X509CA(); // Does X.509 PKI validation of |cert| against the root CA certificate // used when constructing X509CA. This method is thread-safe. util::Status VerifyCert(const X509Cert& cert); // Does X.509 PKI validation of |cert_chain| against the root CA certificate // used when constructing X509CA. This method is thread-safe. util::Status VerifyCertChain(const X509CertChain& cert_chain); // Does X.509 PKI validation of |cert| using the |cert_chain| // certificates. This method allows |cert| to be an ICA. This method is // thread-safe. util::Status VerifyCertWithChain(const X509Cert& cert, const X509CertChain& cert_chain); private: util::Status InitializeStore(); util::Status OpenSslX509Verify(const X509* cert, STACK_OF(X509) * stack); std::unique_ptr ca_cert_; absl::Mutex openssl_store_mutex_; X509_STORE* openssl_store_ GUARDED_BY(openssl_store_mutex_); DISALLOW_IMPLICIT_CONSTRUCTORS(X509CA); }; } // namespace widevine #endif // COMMON_X509_CERT_H_