HTTPS 服务搭建相关概念
目录:
一、相关概念
PEM(Privacy-Enhanced Mail )
The PEM format is the most common format thatCertificate Authoritiesissue certificates in. PEM certificates usually have extentions such as.pem, .crt, .cer, and .key. They are Base64 encoded ASCII files and contain “—–BEGIN CERTIFICATE—–” and “—–END CERTIFICATE—–” statements. Server certificates, intermediate certificates, and private keys can all be put into the PEM format.
Apache and other similar servers use PEM format certificates. Several PEM certificates, and even the private key, can be included in one file, one below the other, but most platforms, such as Apache, expect the certificates and private key to be in separate files.
DER(Distinguished Encoding Rules)
the DER format is simply a binary form of a certificate instead of the ASCII PEM format. It sometimes has a file extension of.derbut it often has a file extension of.cerso the only way to tell the difference between a DER .cer file and a PEM .cer file is to open it in a text editor and look for the BEGIN/END statements. All types of certificates and private keys can be encoded in DER format. DER is typically used withJava platforms. The SSL Converter can only convert certificates to DER format.
PEM is just Distinguished Encoding Rules (DER) that has been Base64 encoded. Used for keys and certificates.
PKCS12 / PFX
The PKCS12 or PFX format is a binary format for storing the server certificate, any intermediate certificates, and the private key in one encryptable file. PFX files usually have extensions such as.pfx and .p12. PFX files are typically used onWindows machinesto import and export certificates and private keys.
PKCS12 is a password-protected format that can contain multiple certificates and keys.
Java KeyStore (JKS)
Java version of PKCS12 and also password protected. Entries in a JKS file must have an “alias” that is unique. If an alias is not specified, “mykey” is used by default. It’s like a database for certs and keys.
CSR (Certificate Signing Request)
A file generated with a private key. A CSR can be sent to a CA to request to be signed. The CA uses its private key to digitally sign the CSR and create a signed cert.It is usually generated on the server where the certificate will be installed and contains information that will be included in the certificate such as the organization name, common name (domain name), locality, and country. It also contains the public key that will be included in the certificate.
X.509
A specification governing the format and usage of certificates.
Certificate (cert)
The public half of a public/private key pair with some additional metadata about who issued it etc. It may be freely given to anyone.
二、通信流程
One-way SSL authentication (server -> client)
Client and server use 9 handshake messages to establish the encrypted channel prior to message exchanging
- Client sendsClientHellomessage proposing SSL options.
- Server responds withServerHellomessage selecting the SSL options.
- Server sendsCertificatemessage, which contains the server’s certificate.
- Server concludes its part of the negotiation withServerHelloDonemessage.
- Client sends session key information (encrypted with server’s public key) inClientKeyExchangemessage.
- Client sendsChangeCipherSpecmessage to activate the negotiated options for all future messages it will send.
- Client sendsFinishedmessage to let the server check the newly activated options.
- Server sendsChangeCipherSpecmessage to activate the negotiated options for all future messages it will send.
- Server sendsFinishedmessage to let the client check the newly activated options.
Two-way SSL authentication (server <-> client)
Client and server use 12 handshake messages to establish the encrypted channel prior to message exchanging:
1. Client sends ClientHello message proposing SSL options.
2. Server responds with ServerHello message selecting the SSL options.
3. Server sends Certificate message, which contains the server’s certificate.
4. Server requests client’s certificate in CertificateRequest message, so that the connection can be mutually authenticated.
5. Server concludes its part of the negotiation with ServerHelloDone message.
6. Client responds with Certificate message, which contains the client’s certificate.
7. Client sends session key information (encrypted with server’s public key) in ClientKeyExchange message.
8. Client sends a CertificateVerify message to let the server know it owns the sent certificate.
9. Client sends ChangeCipherSpec message to activate the negotiated options for all future messages it will send.
10. Client sends Finished message to let the server check the newly activated options.
11. Server sends ChangeCipherSpec message to activate the negotiated options for all future messages it will send.
12. Server sends Finished message to let the client check the newly activated options.
三、证书生成
CA file
- Create a private key of CA
openssl genrsa -out ca-key.pem 1024
- Create a certificate sign request of CA
openssl req -new -out ca-req.csr -key ca-key.pem
- Create self signed certificate
openssl x509 -req -in ca-req.csr -out ca-cert.pem -signkey ca-key.pem -days 365
- Export certificate to pkcs#12 format
openssl pkcs12 -export -clcerts -in ca-cert.pem -inkey ca-key.pem -out ca.p12
type your p12 file password. eg.ca123456
- Create a private key of CA
Client file
- Create a private key of Client
openssl genrsa -out client-key.pem 1024
- Create a certificate sign request of Client
openssl req -new -out client-req.csr -key client-key.pem
type common name use domain or IP, do not use same value with server common name. - Create CA signed certificate
openssl x509 -req -in client-req.csr -out client-cert.pem -signkey client-key.pem
-CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -days 365
- Export certificate to pkcs#12 format
openssl pkcs12 -export -clcerts -in client-cert.pem -inkey client-key.pem -out client.p12
type your p12 file password. eg.c123456
- Create a private key of Client
Server file
- Create a private key of Server
openssl genrsa -out server-key.pem 1024
- Create a certificate sign request of Server
openssl req -new -out server-req.csr -key server-key.pem
type common name use domain or IP, do not use same value with client common name. - Create CA signed certificate
openssl x509 -req -in server-req.csr -out server-cert.pem -signkey server-key.pem
-CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -days 365
- Export certificate to pkcs#12 format
openssl pkcs12 -export -clcerts -in server-cert.pem -inkey server-key.pem
-name "server" -out server.p12
type your p12 file password. eg.s123456
- Create a private key of Server
四、组合证书,生成trustStrore和storeFile
- generate jks file from p12
keytool -importkeystore -deststorepass trust123456 -destkeypass trust123456
-destkeystore server_trust_store.jks -srckeystore server.p12
-srcstoretype PKCS12 -srcstorepass s123456
keep the same of-deststorepass trust123456 -destkeypass trust123456
, or you will get a ‘cannot recover key’ error.
this operation will contain one entry, type is privateKeyEntry. - show certificate in jks.
keytool -list -v -keystore server_trust_store.jks
type jks file passwordtrust123456
import cert to jks file.
keytool -import -v -trustcacerts -keystore server_trust_store.jks -storepass trust123456 -alias cacert -file ca-cert.cert
this operation will add a cert entry to the jks file. then the entry type is trustCertEntry
Java has its own version of PKCS12 called Java KeyStore (JKS). It is also password protected. Entries in a JKS file must have an “alias” that is unique. If an alias is not specified, “mykey” is used by default. It’s like a database for certs and keys.
For both the “KeyStore” and “TrustStore” fields in the REST SSL Account settings, we are going to use JKS files. The difference between them is for terminology reasons: KeyStores provide credentials, TrustStores verify credentials.
Clients will use certificates stored in their TrustStores to verify identities of servers. They will present certificates stored in their KeyStores to servers requiring them.
server and client jks file.
server_key_store.jks:
contains server’s cert.(PrivateKeyEntry)
server_trust_key_store.jks
contains ca’s cert, server.cert.(PrivateKeyEntry)
client_key_store.jks:
contains client’s cert.(PrivateKeyEntry)
client_trust_key_store.jks
contains server’s cert. client.cert(PrivateKeyEntry)
五、java 服务搭建
- 服务端
/**
* Configure embedded Tomcat and SSL connectors
**/
@Configuration
public class Config {
@Autowired
private Environment env; //config file
// Embedded Tomcat with HTTP and HTTPS support
@Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new
TomcatEmbeddedServletContainerFactory();
tomcat.addAdditionalTomcatConnectors(createSSLConnector());
return tomcat;
}
// Creates an SSL connector, sets two-way SSL, key- and trust stores, passwords, ports etc.
protected Connector createSSLConnector() {
Connector connector = new Connector(Http11Protocol.class.getCanonicalName());
Http11Protocol protocol = (Http11Protocol) connector.getProtocolHandler();
connector.setPort(env.getRequiredProperty("ssl.port", Integer.class));
connector.setScheme(env.getRequiredProperty("ssl.scheme")); // https
connector.setSecure(env.getRequiredProperty("ssl.secure", Boolean.class)); //ture or false
//true or false, two way ssl or one way ssl.
protocol.setClientAuth(env.getRequiredProperty("ssl.client-auth"));
protocol.setSSLEnabled(env.getRequiredProperty("ssl.enabled", Boolean.class)); // true
// jks file password, like trust123456
protocol.setKeyPass(env.getRequiredProperty("ssl.key-password"));
protocol.setKeystoreFile(env.getRequiredProperty("ssl.key_store"));// jks file
// jks file password, like trust123456
protocol.setKeystorePass(env.getRequiredProperty("ssl.store-password"));
protocol.setTruststoreFile(env.getRequiredProperty("ssl.trust_key_store"));
protocol.setTruststorePass(env.getRequiredProperty("ssl.store-password"));
//ciphers string, eg TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
protocol.setCiphers(env.getRequiredProperty("ssl.ciphers"));
return connector;
}
- 客户端
public RestTemplate restTemplateHttpsWithCert4node()
throws KeyStoreException,
NoSuchAlgorithmException,
KeyManagementException,
IOException,
CertificateException,
UnrecoverableKeyException {
String storeFilePath = "/path/of/client_store.jks";
String trustStoreFilePath = "/path/of/client_trust_store.jks";
String storeFilePass = "c123456";
SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(getStore(storeFilePath, storeFilePass.toCharArray()),
storeFilePass.toCharArray())
.loadTrustMaterial(getStore(trustStoreFilePath, storeFilePass.toCharArray()),
(TrustStrategy) (x509Certificates, s) -> true)
.useProtocol("TLS")
.build();
SSLConnectionSocketFactory connectionFactory =
new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier());
CloseableHttpClient closeableHttpClient = HttpClientBuilder
.create()
.setSSLSocketFactory(connectionFactory).build();
HttpComponentsClientHttpRequestFactory httpRequestFactory =
new HttpComponentsClientHttpRequestFactory(closeableHttpClient);
RestTemplate template = new RestTemplate(httpRequestFactory);
return template;
}
client test use curl command.
curl -s -v -k https://ip:port/greeting\?name\=kaidi --key client-key.pem --cert client-cert.cert
with option -v
, it will show detial transport communication.
六、nodejs服务搭建
- 服务端
const express = require('express');
const https = require('https');
const fs = require('fs');
const app = express();
const options = {
key: fs.readFileSync('/path/of/server-key.pem'), // server private key
cert: fs.readFileSync('./keys/server/server-cert.pem'), // server cert
ca: fs.readFileSync('./keys/ca/ca-cert.pem'), // ca cert
//passphrase:'123456', // if pfx, needpassphrase
isServer:true,
requestCert: true, // require client cert. true is two way ssl. false is one way.
rejectUnauthorized:true
};
https.createServer(options, app).listen(8888);
app.get('/demo/query/:transId', (req, res) => {
let resStr = req.params['transId'];
let obj = {};
obj.transId = req.params['transId'];
res.setHeader('Content-Type','application/json');
res.send(JSON.stringify(obj));
});
app.post('/demo/loan/', (req, res) => {
let resStr = 'get post request, data ';
resStr += JSON.stringify(req.body);
resStr += ' , and response is good \n';
res.send(resStr);
});
- 客户端(暂缺)