1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
|
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//
//
#pragma once
#include <cstring>
#include <string>
#include <vector>
#include <mbedtls/x509.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/oid.h>
#include "openvpn/common/hexstr.hpp"
#define MBEDTLS_MAX_SUBJECT_LENGTH 256
namespace openvpn::MbedTLSPKI {
/**
* Retrieve the complete X.509 Certificate Subject field
*
* OpenSSL supports two ways of representing the subject line. The old
* format is deprecated, but there might be code expecting this old format.
* The old format looks like this:
*
* /C=KG/ST=NA/O=OpenVPN-TEST/CN=Test-Server/emailAddress=me@myhost.mydomain
*
* The new format is UTF-8 compliant and has a different formatting scheme:
*
* C=KG, ST=NA, O=OpenVPN-TEST, CN=Test-Server,
*emailAddress=me@myhost.mydomain
*
* This mbed TLS implementation supports generating a subject line formatted
* as the deprecated OpenSSL format. This is the default behaviour, to
* preserve OpenSSL compatibility with existing OpenVPN code.
*
* @param cert Pointer to a native mbed TLS X509 object containing the
* certificate
* @param new_format (optional, default: false) Which format to use,
* true indicates the new format
*
* @return Returns a std::string containing the complete certificate subject.
* If it was not possible to retrieve the subject, and empty string
* is returned.
*/
static std::string x509_get_subject(const mbedtls_x509_crt *cert,
bool new_format = false)
{
if (!new_format)
{
// Try to return the x509 subject formatted like the OpenSSL
// X509_NAME_oneline method. Only attributes matched in the switch
// statements below will be rendered. All other attributes will be
// ignored.
std::string ret;
for (const mbedtls_x509_name *name = &cert->subject;
name != nullptr;
name = name->next)
{
const char *key = nullptr;
if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid))
key = "CN";
else if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_COUNTRY, &name->oid))
key = "C";
else if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_LOCALITY, &name->oid))
key = "L";
else if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_STATE, &name->oid))
key = "ST";
else if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_ORGANIZATION, &name->oid))
key = "O";
else if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_ORG_UNIT, &name->oid))
key = "OU";
else if (!MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS9_EMAIL, &name->oid))
key = "emailAddress";
// make sure that key is defined and value has no embedded nulls
if (key && !string::embedded_null((const char *)name->val.p, name->val.len))
ret += "/" + std::string(key)
+ "=" + std::string((const char *)name->val.p, name->val.len);
}
return ret;
}
char tmp_subj[MBEDTLS_MAX_SUBJECT_LENGTH] = {0};
int ret = mbedtls_x509_dn_gets(tmp_subj,
MBEDTLS_MAX_SUBJECT_LENGTH - 1,
&cert->subject);
return (ret > 0 ? std::string(tmp_subj) : std::string(""));
}
/**
* Retrieves just the common name of the X.509 Certificate subject field
*
* @param cert Pointer to a native mbedTLS X509 object containing the
* certificate
*
* @return Returns the contents of the extracted field on success. The
* resulting string may be empty if the extraction failed or the field
* is empty.
*/
static std::string x509_get_common_name(const mbedtls_x509_crt *cert)
{
const mbedtls_x509_name *name = &cert->subject;
// find common name
while (name != nullptr)
{
if (!MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid))
{
break;
}
name = name->next;
}
return (name ? std::string((const char *)name->val.p, name->val.len)
: std::string(""));
}
} // namespace openvpn::MbedTLSPKI
|