• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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