TLS:(Transport Layer Security)為安全傳輸層協(xié)議,所以屬于傳輸層;
SSL與TLS的區(qū)別以及介紹
CA 生成
自動(dòng)生成
- 在OpenSSL的安裝目錄下的misc目錄下,運(yùn)行腳本
/usr/local/etc/openssl@1.1/misc/CA.pl -newca
手動(dòng)生成
無(wú)法進(jìn)行下去了,因?yàn)橹粡闹虚gCA生成開(kāi)始而根CA沒(méi)生成,需要先生成根CA,沒(méi)嘗試過(guò)。
? 創(chuàng)建root CA私鑰和證書(shū)然后進(jìn)一步創(chuàng)建中間CA。為了便于區(qū)分,我們將創(chuàng)建中間CA(intermediate CA)的CA稱為根CA(root CA)。
? 中間CA是root CA的代理,其證書(shū)由root CA簽發(fā),同時(shí)中間CA能夠代表根CA簽發(fā)用戶證書(shū),由此建立起信任鏈。
? 創(chuàng)建中間CA的好處是即使中間CA的私鑰泄露,造成的影響也是可控的,我們只需要使用root CA撤銷對(duì)應(yīng)中間CA的證書(shū)即可。此外root CA的私鑰可以脫機(jī)妥善保存,只需要在撤銷和更新中間CA證書(shū)時(shí)才會(huì)使用。
- 生成 CA 目錄
//mkdir [-p] dirName
//-p 確保目錄名稱存在,不存在的就建一個(gè)
mkdir -p /Users/harleyhuang/Documents/Gitee/SSL/CA
//生成 certs、 crl、 newcerts、 private四個(gè)文件夾
mkdir certs crl newcerts private

//chmod abc file: 文件使用權(quán)限
//a,b,c各為一個(gè)數(shù)字,分別表示User、Group、及Other的權(quán)限。
//若r=4,w=2,x=1,要rwx屬性則4+2+1=7
chmod 777 private
// touch命令用于修改文件或者目錄的時(shí)間屬性,包括存取時(shí)間和更改時(shí)間。若文件不存在,系統(tǒng)會(huì)建立一個(gè)新的文件
touch index.txt
//echo: 指令與 PHP 的 echo 指令類似,都是用于字符串的輸出
//echo "It is a test" > myfile:顯示結(jié)果定向至文件
echo 1000 > serial

- 創(chuàng)建中間CA的私鑰,采用AES-256算法加密中間CA的私鑰,中途會(huì)讓我們輸入加密密鑰,最后修改中間CA的私鑰訪問(wèn)權(quán)限
openssl genrsa -aes256 -out private/cakey.pem 4096
chmod 400 private/cakey.pem

- 中間CA要向root CA申請(qǐng)公鑰證書(shū),就要首先產(chǎn)生一個(gè)CSR(證書(shū)簽名請(qǐng)求,Certificate Signing Request都有作用)格式的請(qǐng)求文件,將其發(fā)送給root CA后等待其對(duì)中間CA的審查。
? 將創(chuàng)建root CA時(shí)使用的配置文件拷貝到中間CA證書(shū)目錄下,該配置文件在生成CSR文件和后續(xù)簽發(fā)用戶證書(shū)時(shí)都有用。
? 創(chuàng)建并編輯intermediate_CA.cnf,若是demoCA中沒(méi)有rootCA.cnf文件夾可以去/System/Library/OpenSSL/openssl.cnf進(jìn)行拷貝一份:
cp /Users/harleyhuang/Documents/Gitee/SSL/demoCA/rootCA.cnf /Users/harleyhuang/Documents/Gitee/SSL/intermediateCA/intermediateCA.cnf
cd cd /Users/harleyhuang/Documents/Gitee/SSL/intermediateCA
vim intermediateCA.cnf
//編輯
...
[ CA_default ]
dir = /Users/harleyhuang/Documents/Gitee/SSL/intermediateCA
今后我們每次使用中間CA創(chuàng)建新的證書(shū)時(shí),以”-config /Users/harleyhuang/Documents/Gitee/SSL/intermediateCA/intermediateCA.cnf“ 的形式告訴OpenSSL中間CA的信息。
intermediateCA.cnf.cnf默認(rèn)申請(qǐng)的有效期是365天,如果想要修改這個(gè)時(shí)長(zhǎng),可以在[ CA_default ]的"default_days"字段進(jìn)行修改。
- 生成CSR文件
cd /Users/harleyhuang/Documents/Gitee/SSL/intermediateCA
openssl req -config intermediateCA.cnf -sha256 -new -key private/cakey.pem -out cacsr.pem

? 隨后系統(tǒng)會(huì)要求我們輸入中間CA的私鑰密碼,設(shè)置中間CA的一些身份信息等等,注意”O(jiān)rganization Name“一項(xiàng)一定要與root CA時(shí)設(shè)置的相同。
? 正確輸入中間CA的身份信息后我們就得到了中間CA的CSR。
? 接下來(lái)我們用root CA同意中間CA的請(qǐng)求,因?yàn)槲覀儗⑹褂胷oot CA的私鑰簽名中間CA的證書(shū),這時(shí)系統(tǒng)會(huì)要求我們輸入root CA的私鑰密碼,選擇簽名證書(shū)如下:
cd /Users/harleyhuang/Documents/Gitee/SSL/demoCA
openssl ca -config rootCA.cnf -extensions v3_ca -notext -md sha256 -in /Users/harleyhuang/Documents/Gitee/SSL/intermediateCA/cacsr.pem -out /Users/harleyhuang/Documents/Gitee/SSL/intermediateCA/cacert.pem
根證書(shū)生成
新建一個(gè)SSL的文件夾
終端定位到這個(gè)文件夾
cd /Users/harleyhuang/Documents/Gitee/SSL創(chuàng)建根證書(shū)密鑰文件(自己做CA)root.key
openssl genrsa -des3 -out root.key


- 創(chuàng)建根證書(shū)的申請(qǐng)文件root.csr
openssl req -new -key root.key -out root.csr
截屏2020-03-15上午9.53.04.png
- 創(chuàng)建一個(gè)自當(dāng)前日期起為期十年的根證書(shū)root.crt
openssl x509 -req -days 3650 -sha1 -extensions v3_ca -signkey root.key -in root.csr -out root.crt


服務(wù)器SSL證書(shū)生成
- 創(chuàng)建服務(wù)器證書(shū)密鑰文件(在SSL文件夾中生成私鑰)
使用openssl工具生成一個(gè)RSA私鑰,
openssl genrsa -des3 -out server.key 2048


? 生成rsa私鑰,des3算法,2048位強(qiáng)度,server.key是秘鑰文件名。
? 注意:生成私鑰,需要提供一個(gè)至少4位的密碼。
- 創(chuàng)建服務(wù)器證書(shū)的申請(qǐng)文件root.csr(生成CSR[證書(shū)簽名請(qǐng)求])
? 生成私鑰之后,便可以創(chuàng)建csr文件了。
? 此時(shí)可以有兩種選擇。理想情況下,可以將證書(shū)發(fā)送給證書(shū)頒發(fā)機(jī)構(gòu)(CA),CA驗(yàn)證過(guò)請(qǐng)求者的身份之后,會(huì)出具簽名證書(shū)(很貴)。另外,如果只是內(nèi)部或者測(cè)試需求,也可以使用OpenSSL實(shí)現(xiàn)自簽名,具體操作如下:
openssl req -new -key server.key -out server.csr
//或者生成如下證書(shū),注意2者不同,這里使用上面的
//openssl req -new -sha256 -x509 -days 365 -key server.key -out server.crt

說(shuō)明:需要依次輸入國(guó)家,地區(qū),城市,組織,組織單位,Common Name和Email。其中Common Name,可以寫(xiě)自己的名字或者域名,如果要支持https,Common Name應(yīng)該與域名保持一致,否則會(huì)引起瀏覽器警告。
- 刪除私鑰中的密碼
在【創(chuàng)建根證書(shū)密鑰文件】過(guò)程中,由于必須要指定一個(gè)密碼。而這個(gè)密碼會(huì)帶來(lái)一個(gè)副作用,那就是在每次Apache啟動(dòng)Web服務(wù)器時(shí),都會(huì)要求輸入密碼,這顯然非常不方便。要?jiǎng)h除私鑰中的密碼,操作如下:
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
- 生成自簽名證書(shū)(創(chuàng)建一個(gè)自當(dāng)前日期起為期十年的根證書(shū))
? 如果你不想花錢讓CA簽名,或者只是測(cè)試SSL的具體實(shí)現(xiàn)。那么,現(xiàn)在便可以著手生成一個(gè)自簽名的證書(shū)了。
? 需要注意的是,在使用自簽名的臨時(shí)證書(shū)時(shí),瀏覽器會(huì)提示證書(shū)的頒發(fā)機(jī)構(gòu)是未知的。
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
自簽名證書(shū)生成
證書(shū)查看

說(shuō)明:crt上有證書(shū)持有人的信息,持有人的公鑰,以及簽署者的簽名等信息。當(dāng)用戶安裝了證書(shū)之后,便意味著信任了這份證書(shū),同時(shí)擁有了其中的公鑰。證書(shū)上會(huì)說(shuō)明用途,例如服務(wù)器認(rèn)證,客戶端認(rèn)證,或者簽署其他證書(shū)。當(dāng)系統(tǒng)收到一份新的證書(shū)的時(shí)候,證書(shū)會(huì)說(shuō)明,是由誰(shuí)簽署的。如果這個(gè)簽署者確實(shí)可以簽署其他證書(shū),并且收到證書(shū)上的簽名和簽署者的公鑰可以對(duì)上的時(shí)候,系統(tǒng)就自動(dòng)信任新的證書(shū)。
- 或者使用根證書(shū)生成crt
openssl x509 -req -days 730 -sha1 -extensions v3_req -CA root.crt -CAkey root.key -CAserial root.csr -CAcreateserial -in server.csr -out server2.crt


- 安裝私鑰和證書(shū)
? 將私鑰(server.key)和證書(shū)文件(server.crt)復(fù)制到Apache的配置目錄下即可,在Mac 10.10系統(tǒng)中,復(fù)制到/etc/apache2/目錄中即可。
- 客戶端利用AF3.0使用自定義證書(shū)
第一步:
// 1.初始化單例類
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy.SSLPinningMode = AFSSLPinningModeCertificate;
// 2.設(shè)置證書(shū)模式
NSString * cerPath = [[NSBundle mainBundle] pathForResource:@"xxx" ofType:@"cer"];
NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[[NSSet alloc] initWithObjects:cerData, nil]];
// 客戶端是否信任非法證書(shū)
mgr.securityPolicy.allowInvalidCertificates = YES;
// 是否在證書(shū)域字段中驗(yàn)證域名
[mgr.securityPolicy setValidatesDomainName:NO];
第二步:使用AFNetworking進(jìn)行請(qǐng)求
AFNetworking首先需要配置AFSecurityPolicy類,AFSecurityPolicy類封裝了證書(shū)校驗(yàn)的過(guò)程
/**
AFSecurityPolicy分三種驗(yàn)證模式:
AFSSLPinningModeNone:只是驗(yàn)證證書(shū)是否在信任列表中
AFSSLPinningModeCertificate:該模式會(huì)驗(yàn)證證書(shū)是否在信任列表中,然后再對(duì)比服務(wù)端證書(shū)和客戶端證書(shū)是否一致
AFSSLPinningModePublicKey:只驗(yàn)證服務(wù)端證書(shū)與客戶端證書(shū)的公鑰是否一致
*/
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
securityPolicy.allowInvalidCertificates = YES;//是否允許使用自簽名證書(shū)
securityPolicy.validatesDomainName = NO;//是否需要驗(yàn)證域名,默認(rèn)YES
AFHTTPSessionManager *_manager = [AFHTTPSessionManager manager];
_manager.responseSerializer = [AFHTTPResponseSerializer serializer];
_manager.securityPolicy = securityPolicy;
//設(shè)置超時(shí)
[_manager.requestSerializer willChangeValueForKey:@"timeoutinterval"];
_manager.requestSerializer.timeoutInterval = 20.f;
[_manager.requestSerializer didChangeValueForKey:@"timeoutinterval"];
_manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringCacheData;
_manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/xml",@"text/xml",@"text/plain",@"application/json",nil];
__weak typeof(self) weakSelf = self;
[_manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential) {
SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
/**
* 導(dǎo)入多張CA證書(shū)
*/
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"cer"];//自簽名證書(shū)
NSData* caCert = [NSData dataWithContentsOfFile:cerPath];
NSArray *cerArray = @[caCert];
weakSelf.manager.securityPolicy.pinnedCertificates = cerArray;
SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
NSCAssert(caRef != nil, @"caRef is nil");
NSArray *caArray = @[(__bridge id)(caRef)];
NSCAssert(caArray != nil, @"caArray is nil");
OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
SecTrustSetAnchorCertificatesOnly(serverTrust,NO);
NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");
NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
__autoreleasing NSURLCredential *credential = nil;
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
if (credential) {
disposition = NSURLSessionAuthChallengeUseCredential;
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
} else {
disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
}
} else {
disposition = NSURLSessionAuthChallengePerformDefaultHandling;
}
return disposition;
}];
上述代碼通過(guò)給AFHTTPSessionManager重新設(shè)置證書(shū)驗(yàn)證回調(diào)來(lái)自己驗(yàn)證證書(shū),然后將自己的證書(shū)加入到可信任的證書(shū)列表中,即可通過(guò)證書(shū)的校驗(yàn)。
創(chuàng)建客戶端證書(shū)密鑰文件client.key
openssl genrsa -des3 -out client.key 2048創(chuàng)建客戶端證書(shū)的申請(qǐng)文件client.csr
openssl req -new -key client.key -out client.csr-
創(chuàng)建一個(gè)自當(dāng)前日期起有效期為兩年的客戶端證書(shū)client2.crt
openssl x509 -req -days 730 -sha1 -extensions v3_req -CA server.crt -CAkey server.key -CAserial server.csr -CAcreateserial -in client.csr -out client2.crt
客戶端證書(shū)client2.crt 生成
發(fā)現(xiàn)它unable to load CA Private Key 將客戶端證書(shū)文件client.crt和客戶端證書(shū)密鑰文件client.key合并成客戶端證書(shū)安裝包c(diǎn)lient.pfx
openssl pkcs12 -export -in client2.crt -inkey client.key -out client.pfx-
保存生成的文件備用,其中server.crt和server.key是配置單向SSL時(shí)需要使用的證書(shū)文件,client.crt是配置雙向SSL時(shí)需要使用的證書(shū)文件,client.pfx是配置雙向SSL時(shí)需要客戶端安裝的證書(shū)文件
.crt文件和.key可以合到一個(gè)文件里面,把2個(gè)文件合成了一個(gè).pem文件(直接拷貝過(guò)去就行了)
參考資料
HTTPS 證書(shū)鏈的驗(yàn)證 US
OpenSSL證書(shū)生成及Mac上Apache服務(wù)器配置HTTPS
搭建CA服務(wù)器 US


