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