在https学习笔记二,已经弄清了数字证书的概念,组成和在https连接过程中,客户端是如何验证服务器端的证书的。这一章,主要介绍下如何使用openssl库来创建key file,以及生成root CA及签发子证书。学习主要参考官方文档:https://www.feistyduck.com/library/openssl-cookbook/online/ch-openssl.html#

一、openssl 简介

openssl 是目前最流行的 SSL 密码库工具,其提供了一个通用、健壮、功能完备的工具套件,用以支持SSL/TLS 协议的实现。官网:https://www.openssl.org/source/,其中有3个主要的用途:1、密码算法库(建立 RSA、DH、DSA key 参数,计算消息摘要,使用各种 Cipher加密/解密) 2、密钥和证书封装管理功能(建立 X.509 证书、证书签名请求(CSR)和CRLs(证书回收列表));3、SSL通信API接口(SSL/TLS 客户端以及服务器的测试,处理S/MIME 或者加密邮件)。

二、安装openssl(linux CentOS7 32位)

如果使用的是unix操作系统,可能安装系统的时候,这个库就已经有且存在了。但是在使用前,需要注意下当前openssl的库的版本。

  1. openssl version
  2. OpenSSL 1.0. Mar

因为版本1.0.1是一个很重要的风水岭版本。因为1.0.1是第一个支持TLS1.1和1.2的版本。支持新的协议。操作系统的选择也很重要,比如Ubuntu 12.04 LTS,客户端不支持SSL2。这里安装以CentOS7系统为例:

A、 下载openssl库文件:https://www.openssl.org/source/

B、将下载的压缩包放在根目录下,解压缩,进入解压缩文件(得到openssl-openssl-1.0.0文件夹)cd openssl-1.0.0

C、编译前配置openssl,执行命令:./config --prefix=/usr/local/openssl,其中 ( --prefix )参数为欲安装之目录,也就是安装后的档案会出现在该目录下。

D、编译openssl,执行命令: make install

  1. 小插曲:安装openssl报错
  2.  
  3. 1、问题描述:安装完成,查看版本信息的时候报错了,缺少一个库文件libssl.so.1.1
  1. [root@b6e4cbd27773 /usr/local/openssl/bin]# openssl version
  2. openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared
  3.  
  4. object file: No such file or directory
    2、解决方法有依赖没装libssl。在/etc/ld.so.conf文件中写入openssl库文件的搜索路径,使用修改后的conf生效即可:
  1. echo "/usr/local/lib64" >> /etc/ld.so.conf
  1. ldconfig -v

三、使用openssl生成RSA密钥对

使用openssl的私钥产生公钥前,需要了解以下几点:

1、key算法:openssl 支持生成RSA,DSA,ECDSA的密钥对,但是RSA是目前使用最普遍的。

2、Key长度:RSA的2048是公认较比较安全的key长度。

3、密码(Passphrase):在key上使用密码是一个可选值,但是一般都是强烈建议的(官网这样写的,实际项目中很多都没有设置口令),这样每次使用key文件时,都需要输入这个密码才能使用,增强了其安全性,但是随之而来的易用性也会变差。

使用genrsa命令来生成RSA key( 产生DSA其他算法的key文件,可以直接参考学习官网教程,在此处以常用的为例),2步骤能完成:

A、生成私钥:

使用命令:openssl genrsa -aes128 -out fd.key 2048 。以下输入了为这个key值设置了密码,且密码使用aes128加密保存。

  1. openssl genrsa -aes128 -out fd.key 2048
  2. Generating RSA private key, 2048 bit long modulus
  3. ....+++
  4. ...................................................................................+++
  5. e is 65537 (0x10001)
  6. Enter pass phrase for fd.key: ****************
  7. Verifying - Enter pass phrase for fd.key: ****************

这个key文件就是私钥文件。可以查看下文件内容:

  1. cat fd.key
  2. -----BEGIN RSA PRIVATE KEY-----
  3. Proc-Type: 4,ENCRYPTED
  4. DEK-Info: AES-128-CBC,01EC21976A463CE36E9DB59FF6AF689A
  5.  
  6. vERmFJzsLeAEDqWdXX4rNwogJp+y95uTnw+bOjWRw1+O1qgGqxQXPtH3LWDUz1Ym
  7. mkpxmIwlSidVSUuUrrUzIL+V21EJ1W9iQ71SJoPOyzX7dYX5GCAwQm9Tsb40FhV/
  8. [21 lines removed...]
  9. 4phGTprEnEwrffRnYrt7khQwrJhNsw6TTtthMhx/UCJdpQdaLW/TuylaJMWL1JRW
  10. i321s5me5ej6Pr4fGccNOe7lZK+563d7v5znAx+Wo1C+F7YgF+g8LOQ8emC+6AVV
  11. -----END RSA PRIVATE KEY-----       

B、生成公钥:

使用命令:openssl rsa -in fd.key -pubout -out fd-public.key

  1. openssl rsa -in fd.key -pubout -out fd-public.key
  2. Enter pass phrase for fd.key: ****************

查看这个key文件,就是公钥:

  1. cat fd-public.key
  2. -----BEGIN PUBLIC KEY-----
  3. MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnlccwQ9FRyJYHM8sFNsY
  4. PUHJHJzhJdwcS7kBptutf/L6OvoEAzCVHi/m0qAA4QM5BziZgnvv+FNnE3sgE5pz
  5. iovEHJ3C959mNQmpvnedXwfcOIlbrNqdISJiP0js6mDCzYjSO1NCQoy3UpYwvwj7
  6. 0ryR1F+abARehlts/Xs/PtX3VamrljiJN6JNgFICy3ZvEhLZEKxR7oob7TnyZDrj
  7. IHxBbqPNzeiqLCFLFPGgJPa0cH8DdovBTesvu7wr/ecsf8CYyUCdEwGkZh9DKtdU
  8. HFa9H8tWW2mX6uwYeHCnf2HTw0E8vjtOb8oYQxlQxtL7dpFyMgrpPOoOVkZZW/P0
  9. NQIDAQAB
  10. -----END PUBLIC KEY-----

四、获取权威机构颁发证书步骤

获取权威机构颁发的证书,需要先得到私钥的key文件(.key),然后使用私钥的key文件生成sign req 文件(.csr),最后把csr文件发给权威机构,等待权威机构认证,认证成功后,会返回证书文件(.crt)。

A:生成私钥key。

与第二节使用openssl生成RSA密钥对的步骤A一致。使用命令:openssl genrsa -aes128 -out fd.key 2048

B:私钥的key文件生成sign req 文件(.csr)

生成csr文件时,需要填写一些关于待签人或者公司的一些信息,比如国家名,省份名,组织机构名,主机名,email名,有些信息可以不填写,使用.标识。

使用命令:openssl req -new -key fd.key -out fd.csr。过程如下:

  1. $ openssl req -new -key fd.key -out fd.csr
  2. Enter pass phrase for fd.key: ****************
  3. You are about to be asked to enter information that will be incorporated
  4. into your certificate request.
  5. What you are about to enter is what is called a Distinguished Name or a DN.
  6. There are quite a few fields but you can leave some blank
  7. For some fields there will be a default value,
  8. If you enter '.', the field will be left blank.
  9. -----
  10. Country Name ( letter code) [AU]:GB
  11. State or Province Name (full name) [Some-State]:.
  12. Locality Name (eg, city) []:London
  13. Organization Name (eg, company) [Internet Widgits Pty Ltd]:Feisty Duck Ltd
  14. Organizational Unit Name (eg, section) []:
  15. Common Name (e.g. server FQDN or YOUR name) []:www.feistyduck.com
  16. Email Address []:webmaster@feistyduck.com
  17.  
  18. Please enter the following 'extra' attributes
  19. to be sent with your certificate request
  20. A challenge password []:
  21. An optional company name []:

C、把csr文件发给权威机构,等待权威机构认证,交费获取证书即可。

五、OpenSSL生成root CA及签发证书

有时候,使用SSL协议是自己内部服务器使用的,这时可以不必去找第三方权威的CA机构做证书,可以做自签证书(自己创建root CA(非权威))主要有以下三个步骤。

A:创建openssl.cnf在使用default-ca时需要使用的SSL的工作目录(第一次必须要设置)。

1、查看openssl的配置文件:

  1. openssl version -a
  2. OpenSSL 1.0.1e-fips Nov
  3. built on: Fri Nov :: CST
  4. platform: linux-x86_64
  5. options: bn(,) md2(int) rc4(16x,int) des(idx,cisc,,int) idea(int) blowfish(idx)
  6. compiler: gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DKRB5_MIT -m64 -DL_ENDIAN -DTERMIO -Wall -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE= -fexceptions -fstack-protector --param=ssp-buffer-size= -m64 -mtune=generic -Wa,--noexecstack -DPURIFY -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
  7. OPENSSLDIR: "/etc/pki/tls"
  8. engines: rdrand dynamic

2、找到OPENSSLDIR: "/etc/pki/tls"的配置文件openssl.cnf

根据配置文件下的[ CA_default ]节点默认值,创建对应文件夹和文件。

按顺序在/etc/pki/CA下执行以下命令创建文件夹和文件:

其中,certs:存放已颁发的证书;newcerts:存放CA指令生成的新证书;private:存放私钥;crl:存放已吊销的整数;index.txt:penSSL定义的已签发证书的文本数据库文件,这个文件通常在初始化的时候是空的;serial:证书签发时使用的序列号参考文件,该文件的序列号是以16进制格式进行存放的,该文件必须提供并且包含一个有效的序列号。

执行完后,当前目录为:

  1. [tt@SWEBMYVMM000210 /etc/pki/CA]$ll
  2. total
  3. drwxrwxrwx root root Mar : certs
  4. drwxrwxrwx root root Nov crl
  5. -rwxrwxrwx root root Mar : index.txt
  6. drwxrwxrwx root root Nov newcerts
  7. drwxrwxrwx root root Nov private
  8. -rwxrwxrwx root root Mar : serial
  1. 小插曲:使用自签证书签名用户证书时报错,文件不存在
  2.  
  3. 1、问题描述:
  4.  
  5.      openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key
  6.  
  7.      Using configuration from /etc/pki/tls/openssl.cnf
  8.  
  9. /etc/pki/CA/serial: No such file or directory
       error while loading serial number
       139996157081440:error:02001002:system library:fopen:No such file or directory:bss_file.c:398:fopen('/etc/pki/CA/serial','r')
       139996157081440:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:400:
  1. 2、问题解决:
    如果不设置工作目录,后续第三步的最后一小步,使用opensslca命令产生用户的ca证书时会报错,创建openssl.cnf在使用default-ca时需要使用的SSL的工作目录即可。

B:生成CA根证书(root ca证书)。

步骤:生成CA私钥(.key)-->生成CA证书请求(.csr)-->自签名得到根证书(.crt)(CA给自已颁发的证书)。

# Generate CA private key   --->ca.key

openssl genrsa -out ca.key 2048

# Generate CSR   --->ca.csr

openssl req -new -key ca.key -out ca.csr

# Generate Self Signed certificate(CA 根证书)  ---> ca.crt

openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt

  1. 小插曲:直接根据key文件获取CA根证书的命令
  2.  
  3. 方法:在得到key文件后,执行以下命令:
    openssl req -new -x509 -days 365 -key fd.key -out fd.crt
    如果不想填写那些注册信息,执行以下命令:
    openssl req -new -x509 -days 365 -key fd.key -out fd.crt subj "/C=GB/L=London/O=Feisty Duck Ltd/CN=www.feistyduck.com

C:用自签根证书 ca.crt  给用户证书签名。

步骤:生成私钥(.key)-->生成证书请求(.csr)-->用CA根证书签名得到证书(.crt)

  1. # private key --->server.key
  2.  
  3. openssl genrsa -out server.key
  1. # generate csr --->server.csr
  2.  
  3. openssl req -new -key server.key -out server.csr
  1. # generate certificate --->server.crt
  1. openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key
  1. 小插曲:用CA根证书签名时报错,The mandatory stateOrProvinceName field was missing
  2. 1、问题描述:
  3. sudo openssl ca -in server.csr -out server.crt -cert ca.crt -keyfile ca.key
  4. Using configuration from /etc/pki/tls/openssl.cnf
  5. Check that the request matches the signature
  6. Signature ok
  7. The mandatory stateOrProvinceName field was missing
  8. 、出现原因:openssl.cnfCA policy有三个match,必须要填一样的,或者改成optional
    3、解决方法:修改配置文件,修改后为:

# For the CA policy
  [ policy_match ]
  countryName = optional
  stateOrProvinceName = optional
  organizationName = optional
  organizationalUnitName = optional
  commonName = supplied
  emailAddress = optional

D:证书的简单使用。

把server.crt以及server.key保存在服务器端等待程序加载使用;把ca.key保存在客户端,如果客户端需要验证服务器端发的证书时使用。

六、遇到过的问题小结

问题1: 对服务器发送https请求失败,连上服务器之后,服务器返回为空。

需求:测试桩实现转发功能,可以按需求处理数据,或者把数据转发给真实的目标环境处理,实现透传转发数据功能,现需要向目标url:https://10.202.2.222:12336/preSvr转发数据。

测试后台服务器写的测试桩,更多的是写服务器端接收处理数据,因为现在桩需要实现透传功能,所以桩是客户端也是服务器端,于是引入了以前测试时使用的客户端,代码如下:

  1.  
  1. class HttpsClient(object):
    def __init__(self, target_ip, target_port,pem_path):
    self.ip = target_ip
    self.port = target_port
    self.pem_path = pem_path
    self.ssl_content =self.get_pem(self.pem_path)
  2.  
  3. def get_pem(self,pem_path):
    '''
    :return: 获取content_ssl
    '''
    context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
    context.set_default_verify_paths()
    context.verify_mode = ssl.CERT_NONE
    # context.load_verify_locations(self.pem_path)
    context.load_verify_locations('C:/Users/Administrator/PycharmProjects/untitled/test/loleina/ca.pem')
    return context
  4.  
  5. def https_send(self,data,timeout=30):
    '''
    '''
  6.  
  7. package = self.__socket_send_recive( self.ssl_content ,data)
    return package
    # return self.__parse_response(package)
  8.  
  9. def __socket_send_recive(self,ssl_content, data,timeout=30):
    '''
  10.  
  11. :param request: 需要发送的内容
    :param type: 请求类型,https type=1 http type=0
    :param timeout: 请求超时时间
    :return: 收到的响应内容
    '''
  12.  
  13. sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(timeout)
    connect_sock = ssl_content.wrap_socket(sock)
    connect_sock.connect((self.ip,int(self.port)))
    connect_sock.send(data)
  14.  
  15. BUFLEN = 1024
    package = ''
    while True:
    buf = connect_sock.recv(BUFLEN)
    package += buf
    # chunked
    if package.find('Transfer-Encoding: chunked') > 0:
    #print 'chunked'
    ls = package.strip().split('\r\n');
    if ls[-1].strip() == '0':
    break;
    else:
    head, body, blength = self.__analyze_package(package);
    # 如果没有分解出head部分,说明返回的不是标准的http协议
    if head is None:
    print 'header is None'
    if len(buf) < BUFLEN:
    break;
    # 100-continue
    elif head.find('Expect: 100-continue') > 0:
    print 'Expect: 100-continue'
    if len(body) >= blength:
    package = package.replace('Expect: 100-continue\r\n', '');
    break;
    else:
    if len(buf) < BUFLEN:
    connect_sock.send('HTTP/1.1 100 Continue\r\n\r\n')
    else:
    pass;
    else:
    # 如果head中没有content-length,
    if blength == -1:
    if len(buf) < BUFLEN:
    break;
    else:
    if len(body) >= blength:
    break;
  16.  
  17. return package
  18.  
  19. def __analyze_package(self, package):
    '''
  20.  
  21. :param package: 收到的socket响应包
    :return: 按照http协议解析出来的(head,body,body长度字段)
    '''
  22.  
  23. idx = package.find('\r\n\r\n');
    # 如果没有发现分隔行,返回None
    if idx < 0:
    return (None, None, None);
    head = package[:idx];
    body = package[idx + 4:];
    blength = -1;
    # 分析body长度
    for ln in head.split('\r\n'):
    if ln.find('Content-Length') == 0:
    blength = ln.replace('Content-Length:', '').strip();
    break;
    return (head, body, int(blength))
  1.  

调用后,就一直收不到真实环境的返回,抓包分析发现3次握手能建立,但是之后服务器端就断开了与客户端的连接。后面换了一个httplib库, httplib.HTTPSConnection获取httpClient后,调用 httpClient.request(method='POST', url=url.path, body=params, headers=headers)调用成功。对比了下2次调用的不同点,更多的不同在发包的时候request有写出资源路径/preSvr,而之前的没写。下面是关键代码段:

  1. url = urlparse(url_str)
  2.  
  3. httpClient = httplib.HTTPSConnection(url.hostname + ':' + str(url.port))
  4. httpClient.host = url.hostname
  5. httpClient.port = url.port
  6. httpClient.key_file = ''
  7. httpClient.cert_file = ''
  8.  
  9. sock = socket.create_connection((httpClient.host, httpClient.port))
  10. httpClient.sock = ssl.wrap_socket(sock, httpClient.key_file, httpClient.cert_file,ssl_version=ssl.PROTOCOL_TLSv1_2)
  11. httpClient.request(method='POST', url=url.path, body=params, headers=headers)
  12. response = httpClient.getresponse().read()

问题2:服务器端返回报文乱码。双方约定好的编码格式就是utf-8,服务器端都正常返回了,客户端收到的数据就是乱码....

当时尝试了各种转码的方法一直都有问题,后面带着问题百度查了下尝试从其他角度来分析问题,后面果然问题是服务器端返回的数据是压缩的,客户端接收到数据后需要解压。

  1. compressedstream = StringIO.StringIO(returnData)
  2. gziper = gzip.GzipFile(fileobj=compressedstream)
  3. returnData = gziper.read()

而之所以返回压缩格式是因为请求包的头文件里有设置Accept-Encoding: deflate, gzip,这条信息代表本地可以接收压缩格式的数据,而服务器在处理时就将大文件压缩再发回客户端。

https学习笔记三----OpenSSL生成root CA及签发证书的更多相关文章

  1. OpenSSL生成root CA及签发证书

    一.openssl 简介 openssl 是目前最流行的 SSL 密码库工具,其提供了一个通用.健壮.功能完备的工具套件,用以支持SSL/TLS 协议的实现.官网:https://www.openss ...

  2. Activiti工作流学习笔记(三)——自动生成28张数据库表的底层原理分析

    原创/朱季谦 我接触工作流引擎Activiti已有两年之久,但一直都只限于熟悉其各类API的使用,对底层的实现,则存在较大的盲区. Activiti这个开源框架在设计上,其实存在不少值得学习和思考的地 ...

  3. HTTPS学习笔记一----HTTPS的基础理论知识

    首先推荐一本书,<HTTP权威指南>我就是看这本书入门的,对http协议有了更好的理解,学习https的理论知识我认为需要了解以下几点,需要一步步的深入学习: 1.HTTPS的基本概念? ...

  4. Oracle学习笔记三 SQL命令

    SQL简介 SQL 支持下列类别的命令: 1.数据定义语言(DDL) 2.数据操纵语言(DML) 3.事务控制语言(TCL) 4.数据控制语言(DCL)  

  5. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  6. JSP学习笔记(三):简单的Tomcat Web服务器

    注意:每次对Tomcat配置文件进行修改后,必须重启Tomcat 在E盘的DATA文件夹中创建TomcatDemo文件夹,并将Tomcat安装路径下的webapps/ROOT中的WEB-INF文件夹复 ...

  7. VSTO学习笔记(三) 开发Office 2010 64位COM加载项

    原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...

  8. Learning ROS for Robotics Programming Second Edition学习笔记(三) 补充 hector_slam

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  9. Typescript 学习笔记三:函数

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

随机推荐

  1. OraclePLSQL编程

    PL/SQL编程 pl/sql(procedural language/sql)是Oracle在标准的sql语言上的扩展.pl/sql不仅允许嵌入式sql语言,还可以定义变量和常量,允许使用条件语句和 ...

  2. [译] 理解 LSTM(Long Short-Term Memory, LSTM) 网络

    本文译自 Christopher Olah 的博文 Recurrent Neural Networks 人类并不是每时每刻都从一片空白的大脑开始他们的思考.在你阅读这篇文章时候,你都是基于自己已经拥有 ...

  3. DB2隔离级别之RR/RS/CS/UR

      1.RR隔离级别:在此隔离级别下. DB2会锁住全部相关的纪录. 在一个SQL语句运行期间, 全部运行此语句扫描过的纪录都会被加上对应的锁.在一个SQL语句运行期间,全部运行此语句扫描过的纪录都会 ...

  4. 神经网络和误差逆传播算法(BP)

    本人弱学校的CS 渣硕一枚,在找工作的时候,发现好多公司都对深度学习有要求,尤其是CNN和RNN,好吧,啥也不说了,拿过来好好看看.以前看习西瓜书的时候神经网络这块就是一个看的很模糊的块,包括台大的视 ...

  5. 在k8s上配置ingress并启用HTTPS证书

    第一步,定义Secret文件 该文件设置tls的证书私钥和公钥内容,通过base64编码的内容 tls.crt: 证书公钥 tls.key: 证书私钥 示例 apiVersion: v1 kind: ...

  6. Linux下的awk文本分析命令实例(一)

    1.  入门实例1.1 显示最近登录的5个帐号: [root@localhost ~]# | awk '{print $1}' root root root root reboot 1.2 如果只是显 ...

  7. phpadmin dvwa sqli-labs xsser.me

    下载phpadmin,安装后网站根目录 phpStudy\PHPTutorial\WWW 将下载的dvwa文件夹放到该目录下,修改config/config.inc.php文件中的mysql连接信息. ...

  8. python处理u开头的字符串

    是用python处理excel过程中,从表格中解析除字符串,打印出来的中文却显示成了u'开头的乱码字符串,在控制台中输出的编码格式是utf-8,而excel表格的数据也是utf-8编码成的,但是解析成 ...

  9. 3D Slicer Modify Mouse Event 修改3D Slicer中的鼠标响应事件

    在3D Slicer中,我们如果想在自己写的插件中来修改默认的鼠标响应事件的话,就需要先将原有的响应事件链接删除,然后建立自定义的响应事件链接,然后将自己要实现的功能写在响应事件函数中. 比如Slic ...

  10. codechef cook 103 div2

    第一次打codechef...不太会用这oj. A: #include <bits/stdc++.h> #define mk(a,b) make_pair(a,b) #define pii ...