Newer
Older
XinYang_IOS / Pods / OpenVPNAdapter / Sources / OpenVPN3 / openvpn / mbedtls / pki / x509certinfo.hpp
@zhangfeng zhangfeng on 7 Dec 2023 4 KB 1.8.0
//    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-2020 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