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