| 187 | } |
| 188 | |
| 189 | CertAndKeyNative makeCertNative(CertSpecRef spec, CertAndKeyNative issuer) { |
| 190 | // issuer key/cert must be both set or both null (self-signed case) |
| 191 | ASSERT(issuer.valid() || issuer.null()); |
| 192 | |
| 193 | auto const isSelfSigned = issuer.null(); |
| 194 | auto keypair = makeEcP256(); |
| 195 | auto newX = ::X509_new(); |
| 196 | OSSL_ASSERT(newX); |
| 197 | auto x509Guard = ScopeExit([&newX]() { |
| 198 | if (newX) |
| 199 | ::X509_free(newX); |
| 200 | }); |
| 201 | auto smartX = std::shared_ptr<X509>(newX, &::X509_free); |
| 202 | newX = nullptr; |
| 203 | auto x = smartX.get(); |
| 204 | OSSL_ASSERT(0 < ::X509_set_version(x, 2 /*X509_VERSION_3*/)); |
| 205 | auto serialPtr = ::X509_get_serialNumber(x); |
| 206 | OSSL_ASSERT(serialPtr); |
| 207 | OSSL_ASSERT(0 < ::ASN1_INTEGER_set(serialPtr, spec.serialNumber)); |
| 208 | auto notBefore = ::X509_getm_notBefore(x); |
| 209 | OSSL_ASSERT(notBefore); |
| 210 | OSSL_ASSERT(::X509_gmtime_adj(notBefore, spec.offsetNotBefore)); |
| 211 | auto notAfter = ::X509_getm_notAfter(x); |
| 212 | OSSL_ASSERT(notAfter); |
| 213 | OSSL_ASSERT(::X509_gmtime_adj(notAfter, spec.offsetNotAfter)); |
| 214 | OSSL_ASSERT(0 < ::X509_set_pubkey(x, keypair.nativeHandle())); |
| 215 | auto subjectName = ::X509_get_subject_name(x); |
| 216 | OSSL_ASSERT(subjectName); |
| 217 | for (const auto& entry : spec.subjectName) { |
| 218 | // field names are expected to null-terminate |
| 219 | auto fieldName = entry.field.toString(); |
| 220 | OSSL_ASSERT(0 < |
| 221 | ::X509_NAME_add_entry_by_txt( |
| 222 | subjectName, fieldName.c_str(), MBSTRING_ASC, entry.bytes.begin(), entry.bytes.size(), -1, 0)); |
| 223 | } |
| 224 | auto issuerName = ::X509_get_issuer_name(x); |
| 225 | OSSL_ASSERT(issuerName); |
| 226 | OSSL_ASSERT(::X509_set_issuer_name(x, (isSelfSigned ? subjectName : ::X509_get_subject_name(issuer.cert.get())))); |
| 227 | auto ctx = X509V3_CTX{}; |
| 228 | X509V3_set_ctx_nodb(&ctx); |
| 229 | ::X509V3_set_ctx(&ctx, (isSelfSigned ? x : issuer.cert.get()), x, nullptr, nullptr, 0); |
| 230 | for (const auto& entry : spec.extensions) { |
| 231 | // extension field names and values are expected to null-terminate |
| 232 | auto extName = entry.field.toString(); |
| 233 | auto extValue = entry.bytes.toString(); |
| 234 | auto extNid = ::OBJ_txt2nid(extName.c_str()); |
| 235 | if (extNid == NID_undef) { |
| 236 | TraceEvent(SevWarnAlways, "MkCertInvalidExtName").suppressFor(10).detail("Name", extName); |
| 237 | throw tls_error(); |
| 238 | } |
| 239 | #ifdef OPENSSL_IS_BORINGSSL |
| 240 | auto ext = ::X509V3_EXT_nconf_nid(nullptr, &ctx, extNid, const_cast<char*>(extValue.c_str())); |
| 241 | #else |
| 242 | auto ext = ::X509V3_EXT_nconf_nid(nullptr, &ctx, extNid, extValue.c_str()); |
| 243 | #endif |
| 244 | OSSL_ASSERT(ext); |
| 245 | auto extGuard = ScopeExit([ext]() { ::X509_EXTENSION_free(ext); }); |
| 246 | OSSL_ASSERT(::X509_add_ext(x, ext, -1)); |
no test coverage detected