• 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_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