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_ALGOR); 43 DEFINE_OPENSSL_OBJECT_POINTER(X509_EXTENSION); 44 DEFINE_OPENSSL_OBJECT_POINTER(X509_NAME); 45 DEFINE_OPENSSL_OBJECT_POINTER(EVP_PKEY_CTX); 46 47 class CertUtilsError { 48 public: 49 enum Error { 50 Ok = 0, 51 BoringSsl, 52 Encoding, 53 MemoryAllocation, 54 InvalidArgument, 55 UnexpectedNullPointer, 56 SignatureFailed, 57 TimeError, 58 }; 59 60 private: 61 Error e_; 62 63 public: CertUtilsError(Error e)64 constexpr CertUtilsError(Error e) : e_(e) {} 65 explicit constexpr operator bool() const { return e_ != Ok; } 66 }; 67 68 struct KeyUsageExtension { 69 bool isSigningKey; 70 bool isEncryptionKey; 71 bool isCertificationKey; 72 }; 73 74 struct BasicConstraintsExtension { 75 bool isCa; 76 std::optional<int> pathLength; 77 }; 78 79 /** 80 * This function allocates and prepares an X509 certificate structure with all of the information 81 * given. Next steps would be to set an Issuer with `setIssuer` and sign it with either 82 * `signCert` or `signCertWith`. 83 * @param evp_pkey The public key that the certificate is issued for. 84 * @param serial The certificate serial number. 85 * @param subject The X509 name encoded subject common name. 86 * @param activeDateTimeMilliSeconds The not before date in epoch milliseconds. 87 * @param usageExpireDateTimeMilliSeconds The not after date in epoch milliseconds. 88 * @param addSubjectKeyIdEx If true, adds the subject key id extension. 89 * @param keyUsageEx If given adds, the key usage extension with the given flags. 90 * @param basicConstraints If given, adds the basic constraints extension with the given data. 91 * @return CertUtilsError::Ok on success. 92 */ 93 std::variant<CertUtilsError, X509_Ptr> 94 makeCert(const EVP_PKEY* evp_pkey, // 95 std::optional<std::reference_wrapper<const std::vector<uint8_t>>> serial, // 96 std::optional<std::reference_wrapper<const std::vector<uint8_t>>> subject, // 97 const int64_t activeDateTimeMilliSeconds, // 98 const int64_t usageExpireDateTimeMilliSeconds, // 99 bool addSubjectKeyIdEx, // 100 std::optional<KeyUsageExtension> keyUsageEx, // 101 std::optional<BasicConstraintsExtension> basicConstraints); // 102 103 /** 104 * Takes the subject name from `signingCert` and sets it as issuer name in `cert`. 105 * if `addAuthKeyExt` is true it also generates the digest of the signing certificates's public key 106 * and sets it as authority key id extension in `cert`. 107 * For self signed certificates pass the same pointer to both `cert` and `signingCert`. 108 * 109 * @param cert 110 * @param signingCert 111 * @param addAuthKeyExt 112 * @return CertUtilsError::Ok on success. 113 */ 114 CertUtilsError setIssuer(X509* cert, const X509* signingCert, bool addAuthKeyExt); 115 116 /** 117 * Takes a certificate, and private signing_key. 118 * Signs the certificate with the latter. 119 */ 120 CertUtilsError signCert(X509* certificate, EVP_PKEY* signing_key); 121 122 enum class Digest { 123 SHA1, 124 SHA224, 125 SHA256, 126 SHA384, 127 SHA512, 128 }; 129 130 enum class Algo { 131 ECDSA, 132 RSA, 133 }; 134 135 enum class Padding { 136 Ignored, 137 PKCS1_5, 138 PSS, 139 }; 140 141 /** 142 * Takes an int64_t representing UNIX epoch time in milliseconds and turns it into a UTCTime 143 * or GeneralizedTime string depending on whether the year is in the interval [1950 .. 2050). 144 * Note: The string returned in the array buffer is NUL terminated and of length 13 (UTCTime) 145 * or 15 (GeneralizedTime). 146 * @param timeMillis 147 * @return UTCTime or GeneralizedTime string. 148 */ 149 std::optional<std::array<char, 16>> toTimeString(int64_t timeMillis); 150 151 /** 152 * Sets the signature specifier of the certificate and the signature according to the parameters 153 * c. Then it signs the certificate with the `sign` callback. 154 * IMPORTANT: The parameters `algo`, `padding`, and `digest` do not control the actual signing 155 * algorithm. The caller is responsible to provide a callback that actually performs the signature 156 * as described by this triplet. 157 * The `padding` argument is ignored if `algo` is Algo::EC. 158 * The `digest` field controls the message digest used, and, in case of RSA with PSS padding, 159 * also the MGF1 digest. 160 * 161 * @param certificate X509 certificate structure to be signed. 162 * @param sign Callback function used to digest and sign the DER encoded to-be-signed certificate. 163 * @param algo Algorithm specifier used to encode the signing algorithm id of the X509 certificate. 164 * @param padding Padding specifier used to encode the signing algorithm id of the X509 certificate. 165 * @param digest Digest specifier used to encode the signing algorithm id of the X509 certificate. 166 * @return CertUtilsError::Ok on success. 167 */ 168 CertUtilsError signCertWith(X509* certificate, 169 std::function<std::vector<uint8_t>(const uint8_t*, size_t)> sign, 170 Algo algo, Padding padding, Digest digest); 171 172 /** 173 * Generates the DER representation of the given signed X509 certificate structure. 174 * @param certificate 175 * @return std::vector<uint8_t> with the DER encoded certificate on success. An error code 176 * otherwise. 177 */ 178 std::variant<CertUtilsError, std::vector<uint8_t>> encodeCert(X509* certificate); 179 180 } // namespace keystore 181