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