1 /* 2 * Copyright 2020, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <openssl/err.h> 20 #include <openssl/x509.h> 21 #include <stdint.h> 22 23 #include <memory> 24 #include <optional> 25 #include <variant> 26 27 namespace keystore { 28 // We use boringssl error codes. Error codes that we add are folded into LIB_USER. 29 // The CertificateUtilsInternallErrorCodes enum should not be used by callers, instead use the 30 // BoringSslError constant definitions below for error codes. 31 using BoringSslError = unsigned long; 32 33 #define DEFINE_OPENSSL_OBJECT_POINTER(name) using name##_Ptr = bssl::UniquePtr<name> 34 35 DEFINE_OPENSSL_OBJECT_POINTER(ASN1_BIT_STRING); 36 DEFINE_OPENSSL_OBJECT_POINTER(ASN1_STRING); 37 DEFINE_OPENSSL_OBJECT_POINTER(ASN1_INTEGER); 38 DEFINE_OPENSSL_OBJECT_POINTER(ASN1_OCTET_STRING); 39 DEFINE_OPENSSL_OBJECT_POINTER(ASN1_TIME); 40 DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY); 41 DEFINE_OPENSSL_OBJECT_POINTER(X509); 42 DEFINE_OPENSSL_OBJECT_POINTER(X509_EXTENSION); 43 DEFINE_OPENSSL_OBJECT_POINTER(X509_NAME); 44 DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY_CTX); 45 46 class CertUtilsError { 47 public: 48 enum Error { 49 Ok = 0, 50 BoringSsl, 51 Encoding, 52 MemoryAllocation, 53 InvalidArgument, 54 UnexpectedNullPointer, 55 SignatureFailed, 56 TimeError, 57 }; 58 59 private: 60 Error e_; 61 62 public: CertUtilsError(Error e)63 constexpr CertUtilsError(Error e) : e_(e) {} 64 explicit constexpr operator bool() const { return e_ != Ok; } 65 }; 66 67 struct KeyUsageExtension { 68 bool isSigningKey; 69 bool isEncryptionKey; 70 bool isCertificationKey; 71 }; 72 73 struct BasicConstraintsExtension { 74 bool isCa; 75 std::optional<int> pathLength; 76 }; 77 78 /** 79 * This function allocates and prepares an X509 certificate structure with all of the information 80 * given. Next steps would be to set an Issuer with `setIssuer` and sign it with either 81 * `signCert` or `signCertWith`. 82 * @param evp_pkey The public key that the certificate is issued for. 83 * @param serial The certificate serial number. 84 * @param subject The X509 name encoded subject common name. 85 * @param activeDateTimeMilliSeconds The not before date in epoch milliseconds. 86 * @param usageExpireDateTimeMilliSeconds The not after date in epoch milliseconds. 87 * @param addSubjectKeyIdEx If true, adds the subject key id extension. 88 * @param keyUsageEx If given adds, the key usage extension with the given flags. 89 * @param basicConstraints If given, adds the basic constraints extension with the given data. 90 * @return CertUtilsError::Ok on success. 91 */ 92 std::variant<CertUtilsError, X509_Ptr> 93 makeCert(const EVP_PKEY* evp_pkey, // 94 std::optional<std::reference_wrapper<const std::vector<uint8_t>>> serial, // 95 std::optional<std::reference_wrapper<const std::vector<uint8_t>>> subject, // 96 const int64_t activeDateTimeMilliSeconds, // 97 const int64_t usageExpireDateTimeMilliSeconds, // 98 bool addSubjectKeyIdEx, // 99 std::optional<KeyUsageExtension> keyUsageEx, // 100 std::optional<BasicConstraintsExtension> basicConstraints); // 101 102 /** 103 * Takes the subject name from `signingCert` and sets it as issuer name in `cert`. 104 * if `addAuthKeyExt` is true it also generates the digest of the signing certificates's public key 105 * and sets it as authority key id extension in `cert`. 106 * For self signed certificates pass the same pointer to both `cert` and `signingCert`. 107 * 108 * @param cert 109 * @param signingCert 110 * @param addAuthKeyExt 111 * @return CertUtilsError::Ok on success. 112 */ 113 CertUtilsError setIssuer(X509* cert, const X509* signingCert, bool addAuthKeyExt); 114 115 /** 116 * Takes a certificate, and private signing_key. 117 * Signs the certificate with the latter. 118 */ 119 CertUtilsError signCert(X509* certificate, EVP_PKEY* signing_key); 120 121 enum class Digest { 122 SHA1, 123 SHA224, 124 SHA256, 125 SHA384, 126 SHA512, 127 }; 128 129 enum class Algo { 130 ECDSA, 131 RSA, 132 }; 133 134 enum class Padding { 135 Ignored, 136 PKCS1_5, 137 PSS, 138 }; 139 140 /** 141 * Takes an int64_t representing UNIX epoch time in milliseconds and turns it into a UTCTime 142 * or GeneralizedTime string depending on whether the year is in the interval [1950 .. 2050). 143 * Note: The string returned in the array buffer is NUL terminated and of length 13 (UTCTime) 144 * or 15 (GeneralizedTime). 145 * @param timeMillis 146 * @return UTCTime or GeneralizedTime string. 147 */ 148 std::optional<std::array<char, 16>> toTimeString(int64_t timeMillis); 149 150 /** 151 * Sets the signature specifier of the certificate and the signature according to the parameters 152 * c. Then it signs the certificate with the `sign` callback. 153 * IMPORTANT: The parameters `algo`, `padding`, and `digest` do not control the actual signing 154 * algorithm. The caller is responsible to provide a callback that actually performs the signature 155 * as described by this triplet. 156 * The `padding` argument is ignored if `algo` is Algo::EC. 157 * The `digest` field controls the message digest used, and, in case of RSA with PSS padding, 158 * also the MGF1 digest. 159 * 160 * @param certificate X509 certificate structure to be signed. 161 * @param sign Callback function used to digest and sign the DER encoded to-be-signed certificate. 162 * @param algo Algorithm specifier used to encode the signing algorithm id of the X509 certificate. 163 * @param padding Padding specifier used to encode the signing algorithm id of the X509 certificate. 164 * @param digest Digest specifier used to encode the signing algorithm id of the X509 certificate. 165 * @return CertUtilsError::Ok on success. 166 */ 167 CertUtilsError signCertWith(X509* certificate, 168 std::function<std::vector<uint8_t>(const uint8_t*, size_t)> sign, 169 Algo algo, Padding padding, Digest digest); 170 171 /** 172 * Generates the DER representation of the given signed X509 certificate structure. 173 * @param certificate 174 * @return std::vector<uint8_t> with the DER encoded certificate on success. An error code 175 * otherwise. 176 */ 177 std::variant<CertUtilsError, std::vector<uint8_t>> encodeCert(X509* certificate); 178 179 } // namespace keystore 180