2016-05-13 31 views
1

クライアント証明書を使用してユーザーを認証するためのDSAPIフィルターを作成しました。ユーザーはプロキシ経由で接続し、プロキシはユーザーの証明書を要求ヘッダーに追加します。PEM_read_bio_X509(時々)が失敗する(OpenSSL 1.0.1p)

#define HDR_SSL_CLIENT_CERT     "SSL_CLIENT_CERT" 

私はApacheをHTTPSプロキシとして使用しています。顧客はNGINXを使用します。私はすでに、nginxのは、スペースの代わりにタブが追加され、それが私のコード

#define BUFFER_SIZE 4096 
char certData[BUFFER_SIZE+1] = {0,}; 

certDataによって解析された証明書をBase64表現(TABSが含まれている前に、私はまた、証明書データが正しい形式を持っていることを確認してきたことを発見しましたときのu私たちはすべての問題を見ていない

BIO * bio = BIO_new(BIO_s_mem()); 
    X509 * clientCert = X509_new(); 
    bio = BIO_new_mem_buf(certData, -1); 
    PEM_read_bio_X509(bio, &clientCert, 0, NULL); 

    if (clientCert == NULL) { 
     debugOut("PEM_read_bio_X509 failed...\n"); 

     if(bio) { 
      BIO_free(bio); 
     } 

     return false; 
    } 

:とスペースを\ nに置き換えられます)

-----BEGIN CERTIFICATE----- 
MIIDOTCCAiGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJERTEO 
MAwGA1UECgwFRE9TWVMxETAPBgNVBAsMCFRSQVZFTEVSMRQwEgYDVQQDDAtUUkFW 
RUxFUiBDQTAeFw0xNjA0MTgxMzA2MjdaFw0yNjA0MTgxMzA2MjdaMBUxEzARBgNV 
BAMMCkdlb3JnIER1bWEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCG 
ctEsl++/4LgK8RJId2NUPJgjFKDl76jp38GNMtcCqt+ADUPvR+suoy/zeuRXs7hw 
25YAx49U/FYFlu3Xlmb57ACyPtbhLPpV2Y8fJ0EXD2pY1G3oEWlKWWk6ErT2vg7V 
ppOajckkx3EmkVrALhQgdOqQDHJ6Y2xQSgpKWGORmoEtYQepJ/LGWBfE4muZjUJk 
euUf0fmHFehMw8X0ErPDFxDuAH+d7kjjUl+EqSQCqLqqrg50GMrM0vKIqyqqbUQF 
wLQYyFllYkj0h1VQ+KhyxwVkq2snR+Z2EJe1A7xsUwY5D/9dVK5ih6xeIrpgvgCd 
6Amx2KF9lh8yEZi1NMPPAgMBAAGjYzBhMB8GA1UdEQQYMBaBFEdlb3JnRHVtYUBz 
dGFkdGRvLmRlMB0GA1UdDgQWBBRIX2fz2ahSFgOCf03W4pn9t/BomjAfBgNVHSME 
GDAWgBR7RJ1HsYOVlc4TOAzeqIqETopeCTANBgkqhkiG9w0BAQsFAAOCAQEALWre 
gJYsSD6i3e4MhJOhR0FFincqdnVEeEoVMr4GDSZRMUPSTjNMTdGLLMFHpU9p/cGZ 
4b30k7dQWhIao7aLIgDOXaATr14fLXrZqRM/MXusd27nFKQRZf1ktrxr0vIZqnw4 
SuniS3NP7SuVEbUeTWU8nVub17aUWX8T4C8yAHKmancSSgMXwFhXTNq0aIvwRzIv 
TzyK0SDXSc68kQkf3evTRvKfvlmQGWXL6BukTGJS1870x3IrDK19Phi5PUYXQtZV 
uwaRg1fRUyPno0GCIZiMxCY4rWy+AaM3CO7Ua5+KEiAdWKrBP6Jd24hZuH8ZhuZ/ 
9u5SSvUA1bGAT02eqQ== 
-----END CERTIFICATE----- 

私はその後certDataからX509を取得するには、次のコードを使用しますApacheでDSAPIを歌います。 NGINXも動作します。しかし時々、PEM_read_bio_X509は失敗し、clientCertは作成されません。

私のコードに間違いがありますか?

PEM_read_bio_X509とNGINXには既知の問題がありますか?

私は現在、openSSL 1.0.1pを使用しています。

UPDATEは:良い面と悪いcertData

:ここでプロキシ

size_t last = certLen - lastblank; 

    while (szHeaderClientCert[j] != '\0') { 
     c = szHeaderClientCert[j]; 
     // skip first and last 'space' char 
     if (j == 10 || j == last) { 
      c = ' '; 
     } else { 
      if (isspace(c) || ('\t' == c)) c = '\n'; 
     } 
     certData[j] = c; 

     if (DEBUGOUT) { 
      putchar (c); 
      ofs << c; 
     } 

     j++; 
    } 

    certData[j+1] = '\0'; 

アップデート2から提出されたよう

char szHeaderAuthToken[MAX_BUF_LEN+1] = {0,}; 

にデータが含まれているタブとスペースを置き換えるコードであります

20160512_145926 GOOD 

-----BEGIN CERTIFICATE----- 
MIIDOTCCAiGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJERTEO 
MAwGA1UECgwFRE9TWVMxETAPBgNVBAsMCFRSQVZFTEVSMRQwEgYDVQQDDAtUUkFW 
RUxFUiBDQTAeFw0xNjA0MTgxMzA2MjdaFw0yNjA0MTgxMzA2MjdaMBUxEzARBgNV 
BAMMCkdlb3JnIER1bWEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCG 
ctEsl++/4LgK8RJId2NUPJgjFKDl76jp38GNMtcCqt+ADUPvR+suoy/zeuRXs7hw 
25YAx49U/FYFlu3Xlmb57ACyPtbhLPpV2Y8fJ0EXD2pY1G3oEWlKWWk6ErT2vg7V 
ppOajckkx3EmkVrALhQgdOqQDHJ6Y2xQSgpKWGORmoEtYQepJ/LGWBfE4muZjUJk 
euUf0fmHFehMw8X0ErPDFxDuAH+d7kjjUl+EqSQCqLqqrg50GMrM0vKIqyqqbUQF 
wLQYyFllYkj0h1VQ+KhyxwVkq2snR+Z2EJe1A7xsUwY5D/9dVK5ih6xeIrpgvgCd 
6Amx2KF9lh8yEZi1NMPPAgMBAAGjYzBhMB8GA1UdEQQYMBaBFEdlb3JnRHVtYUBz 
dGFkdGRvLmRlMB0GA1UdDgQWBBRIX2fz2ahSFgOCf03W4pn9t/BomjAfBgNVHSME 
GDAWgBR7RJ1HsYOVlc4TOAzeqIqETopeCTANBgkqhkiG9w0BAQsFAAOCAQEALWre 
gJYsSD6i3e4MhJOhR0FFincqdnVEeEoVMr4GDSZRMUPSTjNMTdGLLMFHpU9p/cGZ 
4b30k7dQWhIao7aLIgDOXaATr14fLXrZqRM/MXusd27nFKQRZf1ktrxr0vIZqnw4 
SuniS3NP7SuVEbUeTWU8nVub17aUWX8T4C8yAHKmancSSgMXwFhXTNq0aIvwRzIv 
TzyK0SDXSc68kQkf3evTRvKfvlmQGWXL6BukTGJS1870x3IrDK19Phi5PUYXQtZV 
uwaRg1fRUyPno0GCIZiMxCY4rWy+AaM3CO7Ua5+KEiAdWKrBP6Jd24hZuH8ZhuZ/ 
9u5SSvUA1bGAT02eqQ== 
-----END CERTIFICATE----- 


20160512_150227 FAIL 

-----BEGIN CERTIFICATE----- 
MIIDOTCCAiGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBGMQswCQYDVQQGEwJERTEO 
MAwGA1UECgwFRE9TWVMxETAPBgNVBAsMCFRSQVZFTEVSMRQwEgYDVQQDDAtUUkFW 
RUxFUiBDQTAeFw0xNjA0MTgxMzA2MjdaFw0yNjA0MTgxMzA2MjdaMBUxEzARBgNV 
BAMMCkdlb3JnIER1bWEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCG 
ctEsl++/4LgK8RJId2NUPJgjFKDl76jp38GNMtcCqt+ADUPvR+suoy/zeuRXs7hw 
25YAx49U/FYFlu3Xlmb57ACyPtbhLPpV2Y8fJ0EXD2pY1G3oEWlKWWk6ErT2vg7V 
ppOajckkx3EmkVrALhQgdOqQDHJ6Y2xQSgpKWGORmoEtYQepJ/LGWBfE4muZjUJk 
euUf0fmHFehMw8X0ErPDFxDuAH+d7kjjUl+EqSQCqLqqrg50GMrM0vKIqyqqbUQF 
wLQYyFllYkj0h1VQ+KhyxwVkq2snR+Z2EJe1A7xsUwY5D/9dVK5ih6xeIrpgvgCd 
6Amx2KF9lh8yEZi1NMPPAgMBAAGjYzBhMB8GA1UdEQQYMBaBFEdlb3JnRHVtYUBz 
dGFkdGRvLmRlMB0GA1UdDgQWBBRIX2fz2ahSFgOCf03W4pn9t/BomjAfBgNVHSME 
GDAWgBR7RJ1HsYOVlc4TOAzeqIqETopeCTANBgkqhkiG9w0BAQsFAAOCAQEALWre 
gJYsSD6i3e4MhJOhR0FFincqdnVEeEoVMr4GDSZRMUPSTjNMTdGLLMFHpU9p/cGZ 
4b30k7dQWhIao7aLIgDOXaATr14fLXrZqRM/MXusd27nFKQRZf1ktrxr0vIZqnw4 
SuniS3NP7SuVEbUeTWU8nVub17aUWX8T4C8yAHKmancSSgMXwFhXTNq0aIvwRzIv 
TzyK0SDXSc68kQkf3evTRvKfvlmQGWXL6BukTGJS1870x3IrDK19Phi5PUYXQtZV 
uwaRg1fRUyPno0GCIZiMxCY4rWy+AaM3CO7Ua5+KEiAdWKrBP6Jd24hZuH8ZhuZ/ 
9u5SSvUA1bGAT02eqQ== 
-----END CERTIFICATE----- 
20160512_150227 PEM_read_bio_X509 failed... 
+0

ちょうど理解を得るためにプロキシは、TLS接続内のクライアント証明書を予想されたCAと実際に照合し、検証済みの証明書をHTTP要求ヘッダーに追加して処理します。あなたの(図示されていない)コードは、リクエストヘッダからこの証明書を抽出し、それをあなたのコードに送ります。抽出が正しく行われたことを確認しましたか? PEM_read_bio_X509が失敗した場合のcertDataの内容を提供できますか? –

+0

プロキシは、実際に予想されるCAに対してTLS接続内のクライアント証明書を検証し、検証済みの証明書をHTTP要求ヘッダーに追加して処理します。 これは間違いです これを確認しましたか? はい、同じ証明書が何の問題もなく何度も解析され、失敗が発生します。それは失敗につながるものと全く同じです。 certDataの内容を指定できますか。 問題なしで解析されたcertDataとエラーで終了するデータには違いはありません。これが私を怒らせるものです。 –

+1

実際にPEM_read_bio_X509を使用しているのは、例のようにではありません。https://www.openssl.org/docs/manmaster/crypto/pem.htmlを参照してください。この例では、clientCert引数はNULLであるか、またはNULLで初期化されている必要があります。つまり、割り当てられたX509_newオブジェクトではありません。そして、PEM_read_bio_X509からの戻り値を確認する必要があります。 –

答えて

1

スペースを置き換えるために関数が実行された後に、PEMテキストを表示できますか?

これは疑わしいです:

if (j == 10 || j == last) { 
    c = ' '; 

その位置にスペースがある場合、あなたが実際にチェックされていないため。あなたはスペースではないものを上書きすることができます。

そして、これが疑わしい:

if (isspace(c) || ('\t' == c)) c = '\n'; 

例えば、改行の前にスペースがあることが発生した場合、これは簡単にバックツーバック2つの改行を引き起こす可能性があるため。

単一の改行に続く行の末尾にスペースがOKであるが、PEMデータの中央の行に2つの改行は機能せず、もたらすであろう:例えば

unable to load certificate 
27748:error:0906B06B:PEM routines:PEM_get_EVP_CIPHER_INFO:not proc type:pem_lib.c:446: 

。シンプル:ここでは正常に動作します

$ echo "...your bad cert output from above..." | openssl x509 -noout -text 

編集:NGINXがPEMの各行の前にスペースを入れているのを見ました。詳細を覚えていません。しかし、NGINXでHTTP_SSL_CLIENT_RAW_CERTを使用します。

編集2:HTTP_SSL_CLIENT_RAW_CERTは、$ ssl_client_certの代わりにnginxの$ ssl_client_raw_certを使用しています。 $ ssl_client_certを使用すると、PEMデータの各行の先頭からTAB文字を削除する必要があります。

+0

>>しかし、NGINXでHTTP_SSL_CLIENT_RAW_CERTを使用します。 説明できますか?私はそれについて何も見つけることができません。 –

+1

ここをクリックしてください:http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_client_certificate - 下部には変数がリストされています。 $ ssl_client_certと$ ssl_client_raw_certを比較してください。私はHTTP_がCGIの前に付加されていると思います。 Cf。 http://blog.honeybadger.io/how-cookies-and-other-http-headers-get-passed-from-nginx-to-rack-and-into-rails/ for。 –

+0

Thx、Jim。しようとします。 –

0

すべてのヒントと提案をありがとう。

私は自分のコードを書き直しました。これが本当にコモノマー側の問題を解決するかどうかはわかりません。私は今、PEMデータ

#include <boost/algorithm/string.hpp> 
#include <boost/algorithm/string/trim_all.hpp> 

std::string cert_data(szHeaderClientCert); 
boost::erase_all(cert_data, "-----BEGIN CERTIFICATE-----"); 
boost::erase_all(cert_data, "-----END CERTIFICATE-----"); 

if (boost::contains(cert_data, "\t")) 
     boost::replace_all(cert_data, "\t", " "); 

boost::trim_all(cert_data); 
boost::replace_all(cert_data, " ", "\n"); 

std::vector<std::string> vec; 
vec.push_back("-----BEGIN CERTIFICATE-----"); 
vec.push_back(cert_data); 
vec.push_back("-----END CERTIFICATE-----"); 

std::string szCertData = boost::algorithm::join(vec, "\n"); 

をフォーマットし、その後、

BIO * bio = BIO_new(BIO_s_mem()); 
BIO_puts(bio, szCertData.c_str()); 

X509 * clientCert; 

clientCert = PEM_read_bio_X509(bio, NULL, 0, NULL); 
     if (clientCert == NULL) { 

で(有効)の証明書を取得するために、ブーストライブラリを使用してい

...

関連する問題