0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-20 12:12:15 +02:00

mbedtls: Move x509_get_subject() and x509_get_common_name() to an independent file

This is the mbed TLS counter part to the OpenSSL change in
commit e0fd92f30756.  These two methods are generic and not
tied to the MbedTLSContext in any particular way.

This is needed to be able to add a unit test for the x509_get_*()
functions.

Signed-off-by: David Sommerseth <davids@openvpn.net>
This commit is contained in:
David Sommerseth 2019-10-03 12:54:06 +02:00
parent 7900c71f5c
commit fc060bd317
No known key found for this signature in database
GPG Key ID: 86CF944C9671FDF2
2 changed files with 139 additions and 52 deletions

View File

@ -0,0 +1,135 @@
// 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-2019 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
//
#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 {
namespace 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 MbedTLSPKI
} // namespace openvpn

View File

@ -51,6 +51,7 @@
#include <openvpn/ssl/ssllog.hpp> #include <openvpn/ssl/ssllog.hpp>
#include <openvpn/mbedtls/pki/x509cert.hpp> #include <openvpn/mbedtls/pki/x509cert.hpp>
#include <openvpn/mbedtls/pki/x509certinfo.hpp>
#include <openvpn/mbedtls/pki/x509crl.hpp> #include <openvpn/mbedtls/pki/x509crl.hpp>
#include <openvpn/mbedtls/pki/dh.hpp> #include <openvpn/mbedtls/pki/dh.hpp>
#include <openvpn/mbedtls/pki/pkctx.hpp> #include <openvpn/mbedtls/pki/pkctx.hpp>
@ -1140,55 +1141,6 @@ namespace openvpn {
return false; return false;
} }
// 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.
static std::string x509_get_subject(const mbedtls_x509_crt *cert)
{
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;
}
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;
}
if (name)
return std::string((const char *)name->val.p, name->val.len);
else
return std::string("");
}
static std::string status_string(const mbedtls_x509_crt *cert, const int depth, const uint32_t *flags) static std::string status_string(const mbedtls_x509_crt *cert, const int depth, const uint32_t *flags)
{ {
std::ostringstream os; std::ostringstream os;
@ -1246,8 +1198,8 @@ namespace openvpn {
// verify tls-remote // verify tls-remote
if (!self->config->tls_remote.empty()) if (!self->config->tls_remote.empty())
{ {
const std::string subject = TLSRemote::sanitize_x509_name(x509_get_subject(cert)); const std::string subject = TLSRemote::sanitize_x509_name(MbedTLSPKI::x509_get_subject(cert));
const std::string common_name = TLSRemote::sanitize_common_name(x509_get_common_name(cert)); const std::string common_name = TLSRemote::sanitize_common_name(MbedTLSPKI::x509_get_common_name(cert));
TLSRemote::log(self->config->tls_remote, subject, common_name); TLSRemote::log(self->config->tls_remote, subject, common_name);
if (!TLSRemote::test(self->config->tls_remote, subject, common_name)) if (!TLSRemote::test(self->config->tls_remote, subject, common_name))
{ {
@ -1317,7 +1269,7 @@ namespace openvpn {
if (ssl->authcert) if (ssl->authcert)
{ {
// save the Common Name // save the Common Name
ssl->authcert->cn = x509_get_common_name(cert); ssl->authcert->cn = MbedTLSPKI::x509_get_common_name(cert);
// save the leaf cert serial number // save the leaf cert serial number
const mbedtls_x509_buf *s = &cert->serial; const mbedtls_x509_buf *s = &cert->serial;