使用openssl为ssl证书增加“使用者备用名称(DNS)
主要修改在openssl.cnf

确保req下存在以下2行(默认第一行是有的,第2行被注释了)

[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req

确保req_distinguished_name下没有 0.xxx 的标签,有的话把0.xxx的0. 去掉

[ req_distinguished_name ]
countryName              = Country Name (2 letter code)
countryName_default = CN
stateOrProvinceName             = State or Province Name (full name)
stateOrProvinceName_default = ShangHai
localityName              = Locality Name (eg, city)
localityName_default = ShangHai
organizationalUnitName             = Organizational Unit Name (eg, section)
organizationalUnitName_default = Domain Control Validated
commonName         = Internet Widgits Ltd
commonName_max = 64

新增最后一行内容 subjectAltName = @alt_names(前2行默认存在)

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

新增 alt_names,注意括号前后的空格,DNS.x 的数量可以自己加

[ alt_names ]
DNS.1 = abc.example.com
DNS.2 = dfe.example.org
DNS.3 = ex.abcexpale.net

Referenced from:https://blog.51cto.com/colinzhouyj/1566438

openssl - How can i know the CA subject name list which loaded in SSL context - Stack Overflow
the sample code shows you how to extract the Common Name (CN) and Subject Alternate Names (SAN) from the certificate in print_cn_name and print_san_name.

void print_san_name(const char* label, X509* const cert)
{
    int success = 0;
    GENERAL_NAMES* names = NULL;
    unsigned char* utf8 = NULL;

    do
    {
        if(!cert) break; /* failed */

        names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0 );
        if(!names) break;

        int i = 0, count = sk_GENERAL_NAME_num(names);
        if(!count) break; /* failed */

        for( i = 0; i < count; ++i )
        {
            GENERAL_NAME* entry = sk_GENERAL_NAME_value(names, i);
            if(!entry) continue;

            if(GEN_DNS == entry->type)
            {
                int len1 = 0, len2 = -1;

                len1 = ASN1_STRING_to_UTF8(&utf8, entry->d.dNSName);
                if(utf8) {
                    len2 = (int)strlen((const char*)utf8);
                }

                if(len1 != len2) {
                    fprintf(stderr, "  Strlen and ASN1_STRING size do not match (embedded null?): %d vs %d\n", len2, len1);
                }

                /* If there's a problem with string lengths, then     */
                /* we skip the candidate and move on to the next.     */
                /* Another policy would be to fails since it probably */
                /* indicates the client is under attack.              */
                if(utf8 && len1 && len2 && (len1 == len2)) {
                    fprintf(stdout, "  %s: %s\n", label, utf8);
                    success = 1;
                }

                if(utf8) {
                    OPENSSL_free(utf8), utf8 = NULL;
                }
            }
            else
            {
                fprintf(stderr, "  Unknown GENERAL_NAME type: %d\n", entry->type);
            }
        }

    } while (0);

    if(names)
        GENERAL_NAMES_free(names);

    if(utf8)
        OPENSSL_free(utf8);

    if(!success)
        fprintf(stdout, "  %s: <not available>\n", label);    
}

Referenced from:https://stackoverflow.com/questions/38368710/how-can-i-know-the-ca-subject-name-list-which-loaded-in-ssl-context

完整域名 - 维基百科,自由的百科全书
完全限定域名(英语:Fully qualified domain name),缩写为FQDN,又译为完全资格域名、完整领域名称,又称为绝对领域名称(absolute domain name)、 绝对域名,域名的一种,能指定其在域名系统 (DNS) 树状图下的一个确实位置。一个完全资格域名会包含所有域名级别,包括 顶级域名 和 根域名。完整域名这个名称的由来,是因为它没有模糊空间,只能用一种方式来解析。完整域名是因应互联网上需要一个统一识别方式而出现,在1980年代后期快速成长。

完整域名由主机名称与母域名两部分所组成,例如有一部服务器的本地主机名为myhost,而其母域名为example.com,那指向该服务器的完整域名就是myhost.example.com。虽然世界上可能有很多服务器的本地主机名是myhost,但myhost.example.com是唯一的,因此完整域名能识别该特定服务器。

Referenced from:https://zh.wikipedia.org/wiki/%E5%AE%8C%E6%95%B4%E7%B6%B2%E5%9F%9F%E5%90%8D%E7%A8%B1

证书中的DNS指的是X509v3扩展里面的X509v3 Subject Alternative Name;

可以使用命令查看

openssl x509 -text -noout -in 1.crt

输出如下:

X509v3 extensions:

X509v3 Subject Alternative Name: 
    DNS: test.com

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <openssl/bio.h>
#include <openssl/x509v3.h>

int main(int argc, char **argv)
{
    BIO *bio = NULL;

    bio = BIO_new_file(argv[1], "r");
    assert(bio);

    X509 *x = NULL;
    x = PEM_read_bio_X509(bio, NULL, NULL, NULL);
    assert(x);

    GENERAL_NAMES* subjectAltNames = (GENERAL_NAMES*)X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL);

    int cnt = sk_GENERAL_NAME_num(subjectAltNames);
    int i;

    for (i = 0; i < cnt; i++) {
        GENERAL_NAME* generalName = sk_GENERAL_NAME_value(subjectAltNames, i);

        printf("%s\n", ASN1_STRING_data(GENERAL_NAME_get0_value(generalName, NULL)));

    }
}
gcc -lssl a.c
./a.out 1.crt

Referenced from:https://blog.csdn.net/propro1314/article/details/72571807?locationNum=6&fps=1

certificates - Provide subjectAltName to openssl directly on the command line
Example of giving the most common attributes (subject and extensions)
on the command line:

 openssl req -new -subj "/C=GB/CN=foo" \
                  -addext "subjectAltName = DNS:foo.co.uk" \
                  -addext "certificatePolicies = 1.2.3.4" \
                  -newkey rsa:2048 -keyout key.pem -out req.pem

Referenced from:https://security.stackexchange.com/questions/74345/provide-subjectaltname-to-openssl-directly-on-the-command-line