/* * Copyright 2020, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include namespace keystore { // We use boringssl error codes. Error codes that we add are folded into LIB_USER. // The CertificateUtilsInternallErrorCodes enum should not be used by callers, instead use the // BoringSslError constant definitions below for error codes. using BoringSslError = unsigned long; #define DEFINE_OPENSSL_OBJECT_POINTER(name) using name##_Ptr = bssl::UniquePtr DEFINE_OPENSSL_OBJECT_POINTER(ASN1_BIT_STRING); DEFINE_OPENSSL_OBJECT_POINTER(ASN1_STRING); DEFINE_OPENSSL_OBJECT_POINTER(ASN1_INTEGER); DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OCTET_STRING); DEFINE_OPENSSL_OBJECT_POINTER(ASN1_TIME); DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY); DEFINE_OPENSSL_OBJECT_POINTER(X509); DEFINE_OPENSSL_OBJECT_POINTER(X509_EXTENSION); DEFINE_OPENSSL_OBJECT_POINTER(X509_NAME); DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY_CTX); class CertUtilsError { public: enum Error { Ok = 0, BoringSsl, Encoding, MemoryAllocation, InvalidArgument, UnexpectedNullPointer, SignatureFailed, TimeError, }; private: Error e_; public: constexpr CertUtilsError(Error e) : e_(e) {} explicit constexpr operator bool() const { return e_ != Ok; } }; struct KeyUsageExtension { bool isSigningKey; bool isEncryptionKey; bool isCertificationKey; }; struct BasicConstraintsExtension { bool isCa; std::optional pathLength; }; /** * This function allocates and prepares an X509 certificate structure with all of the information * given. Next steps would be to set an Issuer with `setIssuer` and sign it with either * `signCert` or `signCertWith`. * @param evp_pkey The public key that the certificate is issued for. * @param serial The certificate serial number. * @param subject The X509 name encoded subject common name. * @param activeDateTimeMilliSeconds The not before date in epoch milliseconds. * @param usageExpireDateTimeMilliSeconds The not after date in epoch milliseconds. * @param addSubjectKeyIdEx If true, adds the subject key id extension. * @param keyUsageEx If given adds, the key usage extension with the given flags. * @param basicConstraints If given, adds the basic constraints extension with the given data. * @return CertUtilsError::Ok on success. */ std::variant makeCert(const EVP_PKEY* evp_pkey, // std::optional>> serial, // std::optional>> subject, // const int64_t activeDateTimeMilliSeconds, // const int64_t usageExpireDateTimeMilliSeconds, // bool addSubjectKeyIdEx, // std::optional keyUsageEx, // std::optional basicConstraints); // /** * Takes the subject name from `signingCert` and sets it as issuer name in `cert`. * if `addAuthKeyExt` is true it also generates the digest of the signing certificates's public key * and sets it as authority key id extension in `cert`. * For self signed certificates pass the same pointer to both `cert` and `signingCert`. * * @param cert * @param signingCert * @param addAuthKeyExt * @return CertUtilsError::Ok on success. */ CertUtilsError setIssuer(X509* cert, const X509* signingCert, bool addAuthKeyExt); /** * Takes a certificate, and private signing_key. * Signs the certificate with the latter. */ CertUtilsError signCert(X509* certificate, EVP_PKEY* signing_key); enum class Digest { SHA1, SHA224, SHA256, SHA384, SHA512, }; enum class Algo { ECDSA, RSA, }; enum class Padding { Ignored, PKCS1_5, PSS, }; /** * Takes an int64_t representing UNIX epoch time in milliseconds and turns it into a UTCTime * or GeneralizedTime string depending on whether the year is in the interval [1950 .. 2050). * Note: The string returned in the array buffer is NUL terminated and of length 13 (UTCTime) * or 15 (GeneralizedTime). * @param timeMillis * @return UTCTime or GeneralizedTime string. */ std::optional> toTimeString(int64_t timeMillis); /** * Sets the signature specifier of the certificate and the signature according to the parameters * c. Then it signs the certificate with the `sign` callback. * IMPORTANT: The parameters `algo`, `padding`, and `digest` do not control the actual signing * algorithm. The caller is responsible to provide a callback that actually performs the signature * as described by this triplet. * The `padding` argument is ignored if `algo` is Algo::EC. * The `digest` field controls the message digest used, and, in case of RSA with PSS padding, * also the MGF1 digest. * * @param certificate X509 certificate structure to be signed. * @param sign Callback function used to digest and sign the DER encoded to-be-signed certificate. * @param algo Algorithm specifier used to encode the signing algorithm id of the X509 certificate. * @param padding Padding specifier used to encode the signing algorithm id of the X509 certificate. * @param digest Digest specifier used to encode the signing algorithm id of the X509 certificate. * @return CertUtilsError::Ok on success. */ CertUtilsError signCertWith(X509* certificate, std::function(const uint8_t*, size_t)> sign, Algo algo, Padding padding, Digest digest); /** * Generates the DER representation of the given signed X509 certificate structure. * @param certificate * @return std::vector with the DER encoded certificate on success. An error code * otherwise. */ std::variant> encodeCert(X509* certificate); } // namespace keystore