2014-04-09 27 views
3

它看起來像OpenSSL總是顯示「不受支持」的subjectAltName爲「otherName」。從「subjectAltName」證書擴展中讀取「otherName」值

被寫入(均通過M2Crypto,並直接經由openssl.cnf中命令行)的字符串:

1.2.3.4;UTF8:some other identifier 

甩(OpenSSL的X​​509 -in test.crt -noout -text):

   c3:88:36:93:82:58:0c:08:7f 
      Exponent: 65537 (0x10001) 
    X509v3 extensions: 
     X509v3 Subject Alternative Name: 
      othername:<unsupported> 
Signature Algorithm: sha1WithRSAEncryption 
    05:76:d5:fc:d0:44:50:af:39:76:05:b4:cb:b6:99:9f:7c:c0: 

通過OpenSSL的源爲 「英文別名」 Grepping,這個站在給我看(在v3_alt.c):

1:

STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, 
       GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret) 
{ 
    unsigned char *p; 
    char oline[256], htmp[5]; 
    int i; 
    switch (gen->type) 
    { 
     case GEN_OTHERNAME: 
     X509V3_add_value("othername","<unsupported>", &ret); 
     break; 

     case GEN_X400: 
     X509V3_add_value("X400Name","<unsupported>", &ret); 
     break; 

     case GEN_EDIPARTY: 
     X509V3_add_value("EdiPartyName","<unsupported>", &ret); 
     break; 

2:

int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen) 
{ 
    unsigned char *p; 
    int i; 
    switch (gen->type) 
    { 
     case GEN_OTHERNAME: 
     BIO_printf(out, "othername:<unsupported>"); 
     break; 

     case GEN_X400: 
     BIO_printf(out, "X400Name:<unsupported>"); 
     break; 

     case GEN_EDIPARTY: 
     /* Maybe fix this: it is supported now */ 
     BIO_printf(out, "EdiPartyName:<unsupported>"); 
     break; 

所以,我敢打賭,這兩種及以上的從我的嘗試來的經驗知識的意思是我不應該指望的「中文別名」值將可以通過命令行或庫調用正確呈現。這可能是因爲它們是實際編碼的ASN.1字符串。那麼,我該怎麼做呢?人們如何提取這些值?如果它們是實際的ASN.1字符串,是否需要開發人員對它們進行解碼?

回答

7

確實,命令行實用程序不以有意義的方式支持subjectAlternateName(SAN)。但是,圖書館確實支持訪問這些值,並進行編程。

在開始您的具體問題之前,請查看Zakir Durumeric的helpful post on OpenSSL certificate parsing。該文章提供了許多有用的提示。

這是一個完整的程序,我在Linux/OpenSSL 1.0.1h上測試過。它演示瞭如何訪問SAN中的用戶原則名稱(UPN)。 UPN的OID是1.3.6.1.4.1.311.20.2.3。如果您需要查找其他OID,請將您自己的調用添加到OBJ_create,如下所示。

#include <stdio.h> 
#include <stdlib.h> 
#include <openssl/x509.h> 
#include <openssl/x509v3.h> 

static const unsigned char test_cert_der[] = { 
    /* hex bytes of a cert in DER format */ 
}; 

int main() { 
    /* In this example, we're looking for the Microsoft UPN, which is present 
    * in X.509v3 certificates suitable for certificate-based authentication. 
    */ 
    int upn_nid = OBJ_create("1.3.6.1.4.1.311.20.2.3", "UPN", "userPrincipleName"); 

    const unsigned char* in = test_cert_der; 
    X509 *cert = d2i_X509(NULL, &in, sizeof(test_cert_der)); 
    if (cert == NULL) { 
     printf("Error\n"); 
     return 1; 
    } 
    int version = ((int) X509_get_version(cert)) + 1; 
    if (version < 3) { 
     printf("Not a version 3 or later certificate.\n"); 
     return 1; 
    } 
    /* Now, we can look at the extensions. These are already parsed into an internal 
    * format, a result of the call to d2i_X509(). We just need to loop through them, 
    * looking for the SAN. 
    */ 
    X509_EXTENSION *ext; 
    int next = X509_get_ext_count(cert); 
    int i; 
    for (i=0; i < next; i++) { 
     ext = X509_get_ext(cert, i); 
     if (OBJ_obj2nid(ext->object) == NID_subject_alt_name) { 
      /* OK, we found the SAN. Now parse its value as a stack of general names. 
      */ 
      in = ext->value->data; 
      GENERAL_NAMES *names = d2i_GENERAL_NAMES(NULL, &in, ext->value->length); 
      if (names == NULL) { 
       printf("GENERAL_NAMES not found\n"); 
       continue; 
      } 
      int nbr_of_names = sk_GENERAL_NAME_num(names); 
      int j, nid; 
      char *astr; 
      for (j=0; j<nbr_of_names; j++) { 
       /* Each general name has an implicit context tag that identifies its 
       * type. 
       */ 
       const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(names, j); 
       switch (current_name->type) { 
        case GEN_OTHERNAME: 
         /* Is this a UPN? */ 
         nid = OBJ_obj2nid(current_name->d.otherName->type_id); 
         if (nid == upn_nid) { 
          astr = (char*)ASN1_STRING_data(current_name->d.otherName-> 
            value->value.asn1_string); 
         } else { 
          /* TODO: add support for other OIDs here. */ 
          astr = "GEN_OTHERNAME"; 
         } 
         break; 
        case GEN_EMAIL: 
         astr = (char*)ASN1_STRING_data(current_name->d.rfc822Name); 
         break; 
        case GEN_DNS: 
         astr = (char*)ASN1_STRING_data(current_name->d.dNSName); 
         break; 
        case GEN_X400: 
         /* TODO: add support for X400 names here. */ 
         astr = "GEN_X400"; 
         break; 
        case GEN_DIRNAME: 
         /* TODO: add support for directory names here. */ 
         astr = "GEN_DIRNAME"; 
         break; 
        case GEN_EDIPARTY: 
         /* TODO: add support for EDI party names here. */ 
         astr = "GEN_EDIPARTY"; 
         break; 
        case GEN_URI: 
         astr = (char*)ASN1_STRING_data(current_name->d.uniformResourceIdentifier); 
         break; 
        case GEN_IPADD: 
         /* TODO: add support for IP addresses here. */ 
         astr = "GEN_IPADD"; 
         break; 
        case GEN_RID: 
         /* TODO: add support for registered IDs here. */ 
         astr = "GEN_RID"; 
         break; 
        default: 
         astr = "Unknown name type"; 
         break; 
       } 
       printf("name #%d: %s\n", j, astr); 
      } 
      GENERAL_NAMES_free(names); 
     } 
    } 
    X509_free(cert); 
    /* free any resources consumed by call(s) to OBJ_create */ 
    OBJ_cleanup(); 
    return 0; 
} 
+0

的OpenSSL 1.0.1包括用於'OBJ_ms_upn'和'NID_ms_upn'的定義,這稍微簡化了這一點。 – davenpcj