首页 > 其他 > 详细

基于openssl的证书格式转换实验报告

时间:2020-05-04 23:16:13      阅读:91      评论:0      收藏:0      [点我收藏+]

 

 

 

北京电子科技学院

《信息安全工程技术应用》课程设计报告

基于OpenSSL的证书格式转换工具设计与实现                                                                                                                                                                                                                                                                     

 

 技术分享图片

 

 

 

 

 

小组成员姓名:20175119郑楚琪

20175122邱昕

20175129陈尧

  

指导教师:娄家鹏

  

提交时间:202054  

一、设计方案及可行性分析

1、任务简介:

.pem .pfx /.keystore .crt .cer .der 这些格式的文件用openssl命令行的产生方式及查看,了解哪些格式可以互相转换并使用openssl编程实现。

2、openssl简介:

OpenSSL 是一个安全套接字层密码库,囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议,并提供丰富的应用程序供测试或其它目的使用。密钥和证书管理是PKI的一个重要组成部分,OpenSSL为之提供了丰富的功能,支持多种标准。

首先,OpenSSL实现了ASN.1的证书和密钥相关标准,提供了对证书、公钥、私钥、证书请求以及CRL等数据对象的DER、PEM和BASE64的编解码功能。OpenSSL提供了产生各种公开密钥对和对称密钥的方法、函数和应用程序,同时提供了对公钥和私钥的DER编解码功能。并实现了私钥的PKCS#12和PKCS#8的编解码功能。OpenSSL在标准中提供了对私钥的加密保护功能,使得密钥可以安全地进行存储和分发。

OpenSSL实现了对证书的X.509标准编解码、PKCS#12格式的编解码以及PKCS#7的编解码功能。并提供了一种文本数据库,支持证书的管理功能,包括证书密钥产生、请求产生、证书签发、吊销和验证等功能。

3、常见数字证书格式:

1)、pem:Privacy Enhanced Mail,一般为文本格式,以-----BEGIN...开头,以-----END...结尾。中间的内容是 BASE64 编码。这种格式可以保存证书和私钥,有时我们也把PEM 格式的私钥的后缀改为.key以区别证书与私钥。

BEGIN CERTIFICATE指证书,BEGIN RSA PRIVATE KEY为私钥。

2)、der:用二进制der编码方法储存的证书,二进制格式,只有证书信息,没有私钥。

3)、crt:有可能用der,也有可能用pem编码

4)、jks:Java Key Storage,JAVA的专属格式,利用keytool可以进行格式转换。一般用于 Tomcat 服务器。

5)、   PFX 或 P12公钥加密标准 #12 (PKCS#12) 可包含所有私钥、公钥和证书。其以二进制格式存储,也称为 PFX 文件。通常可以将Apache/OpenSSL使用的“KEY文件 + CRT文件”格式合并转换为标准的PFX文件。转换时需要输入PFX文件的加密密码。

4、设计模型:

Python是一种跨平台的计算机程序设计语言。 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。openssl本身有丰富的对证书处理的语句,经过我们小组讨论,可以使用python调用openssl语句,实现对数字证书的格式转换。

二、详细设计思路

1、openssl命令:

1)、openssl查看证书命令:

der:openssl x509 -in certificate.der -inform der -text -noout

pem:openssl x509 -in certificate.pem -text -noout

pfx:openssl pkcs12 -in for-iis.pfx

 

2)、openssl转化格式命令:

der转化为pem

openssl x509 -in cert.crt -inform der -outform pem -out cert.pem

pem转化为der

openssl x509 -in cert.pem -outform der -out cert.der

pfx转化为pem

openssl pkcs12 -in for-iis.pfx -out for-iis.pem -nodes

 

3)、openssl生成证书:

生成rsa私钥:openssl genrsa -out rsa_private.key 2048


生成rsa公钥:openssl rsa -in rsa_private.key -pubout -out rsa_public.key

利用已有的公钥私钥生成证书:openssl req -new -x509 -days 365 -key rsa_private.key -out cert.crt

 

将证书转化为der格式:openssl x509 -in cert.pem -outform der -out cert.der

 技术分享图片

 

2、x509:

 

1) X509_STORE_add_crl

 

将crl添加到X509_STORE中。

 

2) void X509_STORE_set_flags(X509_STORE *ctx, long flags)

 

将flags赋值给ctx里面的flags,表明了验证证书时需要验证哪些项。

 

4)  X509_TRUST_set_default

 

设置默认的X509_TRUST检查函数。

 

5)int X509_verify(X509 *a, EVP_PKEY *r)

 

验证证书的签名。

 

6)  X509_verify_cert

 

验证证书,用法可参考apps/verify.c。

 

7)  X509_verify_cert_error_string

 

根据错误号,获取错误信息。

 

8)  X509_add1_ext_i2d

 

根据具体的扩展项数据结构添加一个扩展项。

 

9)  X509_add_ext

 

X509_EXTENSION堆栈中,在指定位置添加一项。

 

10)X509_ALGOR_dup

 

算法拷贝。

 

11)X509_alias_get0/X509_alias_set1

 

获取/设置别名。

 

12)X509_asn1_meth

 

获取X509的ASN1_METHOD,包括new、free、i2d和d2i函数。

 

13)X509_certificate_type

获取证书和公钥类型。

 

 14)int X509_check_issued(X509 *issuer, X509 *subject);

 

检查subject证书是否由issuer颁发,如果是则返回X509_V_OK,即0。

 

15)X509_check_private_key

 

检查私钥与证书中的公钥是否匹配,匹配返回1。

 

 16)X509_cmp

证书比较。

 

17) int X509_cmp_current_time(ASN1_TIME *s)

 

将s与当前时间进行比较,返回值小于0则s早于当前时间,大于0则s晚与当前时间。

 

18)int X509_cmp_time(ASN1_TIME *ctm, time_t *cmp_time)

 

如果ctm时间在cmp_time之后,则返回值大于0。

 

19) X509_delete_ext

 

删除扩展项堆栈中指定位置的扩展项。

 

20)X509_digest

 

根据指定的摘要算法对X509结构做摘要。

 

20)     X509_dup

 

拷贝函数。

 

21)X509_find_by_issuer_and_serial

 

根据颁发者的X509_NAME名称和证书序列号,在X509堆栈中查找对应的证书并返回。

 

22)  X509_find_by_subject

 

从证书堆栈中根据持有者名字查询证书,并返回。

 

23)X509_get0_pubkey_bitstr

 

获取X509结构中的DER编码的公钥信息。

 

24)X509_load_cert_crl_file

 

加载证书和crl,用于验证证书。

 

25)X509_PURPOSE_get0

 

根据X509_PURPOSE的位置获取对应的X509_PURPOSE。

 

26)X509_PURPOSE_get0_name

 

获取X509_PURPOSE的名字。

 

27)X509_PURPOSE_get0_sname

 

获取X509_PURPOSE的别名。

 

28)X509_PURPOSE_get_by_id

 

根据证书用途ID获取X509_PURPOSE在当前数组(xstandard)或堆栈(xptable)中的位置,如果没有返回-1。

 

29)X509_PURPOSE_get_by_sname

 

根据别名获取对应的X509_PURPOSE在数组或堆栈中的位置。

 

30)X509_PURPOSE_get_count

 

获取所有的X509_PURPOSE个数,包括标准的和用户动态添加的。

 

31)X509_PURPOSE_get_id

 

获取X509_PURPOSE的ID。

 

32)  int X509_PURPOSE_set(int *p, int purpose)

 

检查是否有purpose标识的X509_PURPOSE,并将purpose值写入p。

 

33) STACK_OF(X509_EXTENSION) X509v3_add_ext

 

(STACK_OF(X509_EXTENSION) **x, X509_EXTENSION *ex, int loc)

 

添加扩展项,堆栈操作,将ex表示的扩展项根据loc指定的位置插入到X509_EXTENSION堆栈中。

 

34)  X509v3_delete_ext

 

堆栈操作,去除指定位置的扩展项。

 

35)int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext,

 

unsigned long flag, int indent)

 

本函数用于打印单个扩展项,out为BIO类型的输出对象,ext为扩展项,flag表明不支持扩展项的处理方式,indent表明输出时第一列的位置。

 

flag的值在x509v3.h中定义,可以有:

 

#define X509V3_EXT_DEFAULT     0  

 

打印DER编码内容,调用M_ASN1_OCTET_STRING_print。

 

#define X509V3_EXT_ERROR_UNKNOWN        (1L << 16)

 

打印一行语句。

 

#define X509V3_EXT_PARSE_UNKNOWN        (2L << 16)   

 

分析扩展项的DER编码,并打印。

 

#define X509V3_EXT_DUMP_UNKNOWN         (3L << 16)

 

打印出DER编码的内容,调用BIO_dump_indent。

 

36)int X509V3_extensions_print(BIO *bp, char *title,

 

STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent)

 

本函数将堆栈中的所有扩展项打印,参数意义同上。

 

37)  int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *sk, int crit, int lastpos)

 

获取扩展项在堆栈中的位置,crit表面扩展项是否关键,lastpos为指定堆栈搜索起始位置。此函数从给定的lastpos开始搜索扩展项堆栈,找到与crit匹配的扩展项后,返回其位置,如果找不到扩展项,返回-1。

 

38)int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, int nid,int lastpos)

 

获取扩展项在其堆栈中的位置,此函数根据扩展项标识nid以及堆栈搜索的起始进行搜索,如果找到,返回它在堆栈中的位置,如果没找到,返回-1。

 

39)  int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *sk, ASN1_OBJECT *obj, int lastpos)

40)X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x,

 

int loc)

 

获取扩展项,loc为扩展项在堆栈x中的位置,如果不成功,返回NULL。

 

41)int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x)

 

获取扩展项的个数,此函数调用堆栈操作sk_X509_EXTENSION_num(x)来获取扩展项的个数。

 

42)STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section)

 

获取配置信息,section为配置信息中的“段”信息。比如有配置信息如下:

 

[CA]

 

Name1=A

 

Name2=B

 

则section应是”CA”,返回的信息为它包含的内容信息。

 

43)char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section)

 

调用此函数时name为”Name1”,sectionwei “CA”,则返回值为”A”。

 

44)int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool)

 

判断配置信息的布尔值,如果value表示的值为true、TRUE、y、Y、yes、YES,*asn1_bool 的值设为xff,并返回1,如果为false、FALSE、n、N、NO、no, *asn1_bool设置为 0,并返回1。此函数调用不成功时返回0。

 

45) int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint)

 

将value中的值转换为ASN1_INTEGER类型,结果存放在**aint中,函数调用成功返回1,否则返回0。

46)STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line)

 

3、pem:

1)、 PEM_write_XXXX/PEM_write_bio_XXXX

将XXXX代表的信息类型写入到文件/bio中。

2)、 PEM_read_XXXX/PEM_read_bio_XXXX

从文件/bio中读取PEM的XXXX代表类型的信息。

XXXX可用代表的有:SSL_SESSION、X509、X509_REQ、X509_AUX、X509_CRL、RSAPrivateKey、RSAPublicKey、DSAPrivateKey、PrivateKey、PKCS7、DHparams、NETSCAPE_CERT_SEQUENCE、PKCS8PrivateKey、DSAPrivateKey、DSA_PUBKEY、DSAparams、ECPKParameters、ECPrivateKey、EC_PUBKEY等。

3)、 PEM_ASN1_read/PEM_ASN1_read_bio

比较底层的PEM读取函数,2)中的函数都调用了这两个函数。

4)、 PEM_ASN1_write/PEM_ASN1_write_bio

比较底层的PEM读取函数,1)中的函数都调用了这两个函数。

5)、 PEM_read_bio

读取PEM文件的各个部分,包括文件类型、头信息以及消息体(base64解码后的结果)。

6)、PEM_get_EVP_CIPHER_INFO

根据头信息获取对称算法,并加载初始化向量iv。

7)、 PEM_do_header

根据对称算法,解密数据。

8)、PEM_bytes_read_bio

获取PEM数据,得到的结果为一个DER编码的明文数据,该函数先后调用了5)、6)和7)函数。

 

 

4、python程序流程图:

 

 技术分享图片

三、设计特色

1、使用了python语句,易读易维护

2、可以被Java调用

四、源代码及注释(没代码的不用写)

def set_win_center(root, curWidth=200, curHight=200):
    ‘‘‘
   
设置窗口大小,并居中显示
    :param root:主窗体实例
    :param curWidth:窗口宽度,非必填,默认200
    :param curHight:窗口高度,非必填,默认200
    :return:无
    ‘‘‘
   
if not curWidth:
        ‘‘‘获取窗口宽度,默认200‘‘‘
        curWidth = root.winfo_width()
    if not curHight:
        ‘‘‘获取窗口高度,默认200‘‘‘
        curHight = root.winfo_height()
    # print(curWidth, curHight)

    # 获取屏幕宽度和高度
    scn_w, scn_h = root.maxsize()
    # print(scn_w, scn_h)

    # 计算中心坐标
    cen_x = (scn_w - curWidth) / 2
    cen_y = (scn_h - curHight) / 2
    # print(cen_x, cen_y)

    # 设置窗口初始大小和位置
    size_xy = ‘%dx%d+%d+%d‘ % (curWidth, curHight, cen_x, cen_y)
    root.geometry(size_xy)


def pem_2_der():
    os.system("openssl x509 -outform der -in " + w1.get() + " -out " + w2.get())
    tkinter.messagebox.showinfo(title=‘提示‘, message=‘转换成功!‘)

def pem_2_p7b():
    os.system("openssl crl2pkcs7 -nocrl -certfile " + w1.get() + " -out " + w2.get())
    tkinter.messagebox.showinfo(title=‘提示‘, message=‘转换成功!‘)

def pem_2_pfx():
    os.system("openssl pkcs12 -export -in " + w1.get() + "-inkey " +e1.get()+" -out " + w2.get())
    tkinter.messagebox.showinfo(title=‘提示‘, message=‘转换成功!‘)

def pem_2_keystore():
    os.system("keytool -import -file " + w1.get() + "-keystore " + w2.get() +"; y ;")
    tkinter.messagebox.showinfo(title=‘提示‘, message=‘转换成功!‘)

def der_2_pem():
    os.system("openssl x509 -inform der -in " + w1.get() + " -out " + w2.get())
    tkinter.messagebox.showinfo(title=‘提示‘, message=‘转换成功!‘)

def p7b_2_pem():
    os.system("openssl pkcs7 -print_certs -in " + w1.get() + " -out " + w2.get())
    tkinter.messagebox.showinfo(title=‘提示‘, message=‘转换成功!‘)

def pfx_2_pem():
    os.system("openssl pkcs12 -in " + w1.get() + " -out " + w2.get() + " -nodes ;" + e2.get() + ";")
    tkinter.messagebox.showinfo(title=‘提示‘, message=‘转换成功!‘)

def choose_file():
    """
   
选择需要处理的文件
    :return:
    """
   
"""打开选择文件夹对话框"""
    filepath = filedialog.askopenfilename(title=u‘选择被检测文件‘, initialdir=(os.path.abspath("..")))  # 获得选择好的文件
    w1.set(filepath)
    return filepath


def save_file():
    path = filedialog.asksaveasfilename(title=u‘保存文件‘,
                                        initialfile="{}.".format(
                                            datetime.strftime(datetime.now(), "%Y-%m-%d %H-%M-%S")))  # 保存文件路径对话框
    w2.set(path)
    return path


window = tkinter.Tk()


# 第2步,给窗口的可视化起名字
window.title(‘openssl证书格式转换工具‘)
# 第3步,设定窗口的大小(长 * 宽)
set_win_center(window, 720, 550)

w1 = tkinter.StringVar()
w1.set(‘输入文件路径‘)
w2 = tkinter.StringVar()
w2.set(‘输出文件路径‘)
tkinter.Entry(window, show=None, font=(‘楷体‘, 14), textvariable=w1).place(x=80, y=48, anchor=‘nw‘,
                                                                         width=500,
                                                                         height=35)
tkinter.Entry(window, show=None, font=(‘楷体‘, 14), textvariable=w2).place(x=80, y=98, anchor=‘nw‘,
                                                                         width=500,
                                                                         height=35)
tkinter.Button(window, text=‘选择文件‘, font=(‘宋体‘, 14), command=choose_file).place(x=600, y=50, anchor=‘nw‘)
tkinter.Button(window, text=‘保存位置‘, font=(‘宋体‘, 14), command=save_file).place(x=600, y=100, anchor=‘nw‘)

tkinter.Button(window, text=‘pem转der‘, font=(‘宋体‘, 14), command=pem_2_der).place(x=80, y=200, anchor=‘nw‘)
tkinter.Button(window, text=‘pem转p7b‘, font=(‘宋体‘, 14), command=pem_2_p7b).place(x=190, y=200, anchor=‘nw‘)
tkinter.Button(window, text=‘pem转pfx‘, font=(‘宋体‘, 14), command=pem_2_pfx).place(x=290, y=200, anchor=‘nw‘)
tkinter.Button(window, text=‘pem转keystore‘, font=(‘宋体‘, 14), command=pem_2_keystore).place(x=390, y=200, anchor=‘nw‘)
tkinter.Button(window, text=‘der转pem‘, font=(‘宋体‘, 14), command=der_2_pem).place(x=80, y=250, anchor=‘nw‘)
tkinter.Button(window, text=‘p7b转pem‘, font=(‘宋体‘, 14), command=p7b_2_pem).place(x=190, y=250, anchor=‘nw‘)
tkinter.Button(window, text=‘pfx转pem‘, font=(‘宋体‘, 14), command=pfx_2_pem).place(x=290, y=250, anchor=‘nw‘)
e1 = tkinter.Entry(window, show=‘*‘, font=(‘Arial‘, 14))   # 显示成密文形式
e2 = tkinter.Entry(window, show=None, font=(‘Arial‘, 14))  # 显示成明文形式
e1.place(x=80,y=300)
e2.place(x=80,y=350)

l = tkinter.Label(window, text=‘保存位置请自己加上文件名后缀‘, font=(‘Arial‘, 12), width=30, height=2)
# 说明: bg为背景,font为字体,width为长,height为高,这里的长和高是字符的长和高,比如height=2,就是标签有2个字符这么高

# 第5步,放置标签
l.place(x=80, y=150, anchor=‘nw‘) # Label内容content区域放置位置,自动调节尺寸
# 放置lable的方法有:1)l.pack(); 2)l.place();

# 主窗口循环显示
window.mainloop()


五、个人报告

  1. 小组贡献排序及依据:
    邱昕(40%):实现代码,查阅资料。

郑楚琪(40%):实现c语言代码,完成总结报告,调试代码命令

陈尧(20%):搜集资料,完成任务,学习代码和openssl命令知识。

2、个人报告

附:20175119郑楚琪个人报告:

https://www.cnblogs.com/20175129cy/p/12828497.html

      20175129陈尧个人报告:

https://www.cnblogs.com/20175119zcq/p/12828513.html     

 20175122邱昕个人报告:

https://www.cnblogs.com/qiuxin/p/12827541.html

六、参考文献:

【1】《openssl与网络信息安全——基础、结构和指令》

【2】《openssl编程》

【3】https://www.cnblogs.com/chevin/p/11041763.html

【4】https://stackoverflow.com/questions/256405/programmatically-create-x509-certificate-using-openssl/15082282#15082282

基于openssl的证书格式转换实验报告

原文:https://www.cnblogs.com/20175129cy/p/12828597.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!