2015-11-06 78 views
1

我想在Node.js中使用HTTP自簽名證書。不能在Node.js中使用IP作爲自簽名證書

我使用,我已經寫了下面的腳本生成的證書:

generate.sh

#!/bin/bash 
read -p "FQDN: " FQDN 

# for easy testing 
rm ROOT.* 
rm SERVER.* 

openssl genrsa 4096 > ROOT.key 
openssl req -x509 -nodes -sha256 -new -key ROOT.key -days 365 -subj "/C=AU/CN=example" > ROOT.crt 

openssl req -newkey rsa:4096 -nodes -sha256 -keyout SERVER.key -subj "/C=AU/CN=${FQDN}" > SERVER.csr 
openssl x509 -days 365 -req -in SERVER.csr -CA ROOT.crt -CAkey ROOT.key -CAcreateserial > SERVER.crt 

而且我嘗試使用下面的測試證書:

test.js

let fs = require('fs') 
let https = require('https') 

// HTTP server 
https.createServer({ 
    key: fs.readFileSync('SERVER.key'), 
    cert: fs.readFileSync('SERVER.crt'), 
    ca: fs.readFileSync('ROOT.crt') 
}, function (req, res) { 
    res.writeHead(200) 
    res.end('Hello world') 
}).listen(4433) 

// HTTP request 
let req = https.request({ 
    hostname: '127.0.0.1', 
    port: 4433, 
    path: '/', 
    method: 'GET', 
    ca: fs.readFileSync('ROOT.crt') 
}, function (res) { 
    res.on('data', function (data) { 
    console.log(data.toString()) 
    }) 
}) 
req.end() 

然而,在測試:

> node test.js 
Error: Hostname/IP doesn't match certificate's altnames: "IP: 127.0.0.1 is not in the cert's list: " 

這似乎很奇怪,因爲如果我打印證書列表中的證書,則說明該IP是嗎?

如果我使用localhost作爲FQDN和host(在請求中),它確實有效。

我錯過了什麼?

編輯:

curl --cacert ROOT.crt https://127.0.0.1:4433完成,沒有錯誤,那麼我在Node.js的代碼所缺少?

回答

2

感謝Kris Reeves指引我朝着正確的方向前進。

問題出在前面提到的,證書丟失了subjectAltName s,並且讓它們以Node兼容的格式並非如此簡單(必須與X509v3兼容)。

最後Makefile最後成爲這樣的:

.PHONY: clean default 

FQDN ?= 127.0.0.1 

default: SERVER.crt 
clean: 
    rm -f openssl.conf 
    rm -f ROOT.* 
    rm -f SERVER.* 

openssl.conf: 
    cat /etc/ssl/openssl.cnf > openssl.conf 
    echo "[ san_env ]" >> openssl.conf 
    echo "subjectAltName=$$""{ENV::SAN}" >> openssl.conf 

ROOT.key: 
    openssl genrsa 4096 > ROOT.key 

ROOT.crt: ROOT.key 
    openssl req \ 
     -new \ 
     -x509 \ 
     -nodes \ 
     -sha256 \ 
     -key ROOT.key \ 
     -days 365 \ 
     -subj "/C=AU/CN=example" \ 
     -out ROOT.crt 

SERVER.csr: openssl.conf 
    SAN=IP:$(FQDN) openssl req \ 
     -reqexts san_env \ 
     -config openssl.conf \ 
     -newkey rsa:4096 \ 
     -nodes -sha256 \ 
     -keyout SERVER.key \ 
     -subj "/C=AU/CN=$(FQDN)" \ 
     -out SERVER.csr 

SERVER.crt: openssl.conf ROOT.key ROOT.crt SERVER.csr 
    SAN=IP:$(FQDN) openssl x509 \ 
     -req \ 
     -extfile openssl.conf \ 
     -extensions san_env \ 
     -days 365 \ 
     -in SERVER.csr \ 
     -CA ROOT.crt \ 
     -CAkey ROOT.key \ 
     -CAcreateserial \ 
     -out SERVER.crt 

希望這可以幫助其他人誰願意使用自簽名證書只有一個IP。

$ make FQDN=127.0.0.1

+0

'Makefile:7:*** missing separator。 Stop' – MixerOID

1

我在IRC上與您交談,但我會留下信息以防萬一它幫助別人。

通過對節點的TLS模塊的源代碼,我們可以看到,它期望的altnames是在一個非常特殊的格式:

https://github.com/nodejs/node/blob/v5.0.0/lib/tls.js#L108-L145

特別行: var option = altname.match(/^(DNS|IP Address|URI):(.*)$/);

後來,它決定被檢查的主機的格式,如果它是一個IP地址,它會從它從altnames中提取的IP地址中查找它。所以,除非它具有格式「IP地址:127.0.0.1」的altname,否則證書將失敗,因爲這是Node節點將其放入IP列表的唯一方式,它會在稍後識別它正在測試IP地址時檢查它。

我不知道這是否是一個證書的altnames字段的格式,但它應該爲您提供一個路徑來生成Node將接受的證書。

或者,你可以在你的插座或http請求的連接選項提供自己的checkServerIdentity功能(應該得到傳遞給插座):

https://github.com/nodejs/node/blob/82022a79b035c25f8a41df1f2a20793d356c1511/lib/_tls_wrap.js#L962-L969

這是怎麼了,我不得不這樣做它之前,但我相信altname匹配可能比我上次遇到此問題時更新。