openssl3.2 - 官方demo学习 - pkcs12 - pkwrite.c

文章目录

openssl3.2 - 官方demo学习 - pkcs12 - pkwrite.c

概述

openssl3.2 - 官方demo学习 - 索引贴

上次PKCS12的官方实验还没做, 原因是没在官方demo中看到如何生成P12的证书, 因为P12是受密码保护的, 如果不知道密码, 随便拿来一个.P12证书, 用编程也操作不了.

整理了官方帮助文件(openssl3.2 - 帮助文档的整理)后, 很容易就找到了官方说明, 如何用openssl命令行去生成P12证书的全流程操作.

今天拿官方demo pkwrite.c + 自己做的服务器证书来做实验, 学到东西了.

学到的知识点

  • 如果要操作的.PEM文件有密码保护, 在PEM_read_PrivateKey()调用时, 要给密码回调处理, 回调的返回值是密码长度.
  • 并不是只有.P12证书才可以收密码保护, 私钥证书也可以受密码保护. 从PEM_read_PrivateKey()的函数定义就能看出来.
c 复制代码
// 如果私钥证书受密码保护, 那么就要在参数3给出负责密码赋值的回调
EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb,
                              void *u)
{
    return PEM_read_PrivateKey_ex(fp, x, cb, u, NULL, NULL);
}

等后续再看看生成私钥时, 如何给密码保护.

笔记

PEM证书可以拼接

按照官方实验, 生成的证书和私钥是分开的.

pkwrite.c里面是从一个.pem中载入证书和私钥.

因为.PEM是文本格式的, openssl在一个文本文件(.PEM)中载入对应内容时, 是按照文本标签来载入的.

所以, 可以自己将证书和私钥贴在一起.

从newcert.pem拷贝一份pem, 命名为newcert_and_key.pem.

然后将newkey.pem的内容贴在 newcert_and_key.pem的后面, 这个PEM证书就可以用来做pkwrite.c的实验.

也可以将pkwrite.c改一下, 从2个.pem中, 分别载入cert和key. 看自己喜好.

bash 复制代码
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            04:ac:e1:ce:5b:5f:48:56:2c:45:92:46:fb:ed:ca:dc:0e:f2:4f:47
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=CN, ST=SX, O=KRGY, OU=RD, CN=MY_CA/emailAddress=test@sina.com
        Validity
            Not Before: Jan 31 11:00:37 2024 GMT
            Not After : Jan 30 11:00:37 2025 GMT
        Subject: C=CN, ST=SX, L=TY, O=KRGY, OU=server_cert, CN=SERVER_CERT1/emailAddress=test@sina.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:a3:9a:66:9e:cc:73:0b:b0:b8:ed:1f:20:84:43:
                    74:8e:5b:cb:cf:e7:f2:ae:ed:fa:1f:47:23:39:58:
                    74:64:1d:d9:28:10:33:61:36:a3:6e:13:9c:42:70:
                    a2:90:37:2f:4a:e8:16:89:ec:d9:55:a5:70:04:9c:
                    a6:a2:09:81:25:b6:f7:b6:c6:5c:8d:06:c8:8a:17:
                    83:fa:c9:84:4f:67:6f:29:ef:50:a9:6f:cf:40:02:
                    cc:9f:2e:21:5c:99:b0:b6:d2:37:f3:42:5f:7a:ec:
                    b3:2c:d3:10:62:fa:32:b9:cc:94:23:b2:fa:bb:8c:
                    03:b4:51:59:7c:5c:39:e2:11:68:3c:3d:a2:c6:c5:
                    31:00:40:c9:10:46:47:fc:ef:0c:ec:39:f2:cc:29:
                    de:13:66:07:ca:87:bf:bd:7a:43:0b:3a:91:09:f4:
                    7d:e5:c4:fd:08:89:0b:7c:bd:81:69:0b:f6:17:ec:
                    f9:bc:2c:23:62:01:b2:a9:90:bb:13:3e:84:b2:14:
                    57:11:d3:04:97:8c:3b:99:b0:3d:ee:99:dd:a9:f1:
                    a0:14:75:21:6e:9b:ae:01:fc:f3:3f:9b:70:89:1e:
                    a8:d5:98:8a:9f:8d:6d:95:d7:93:6e:13:71:70:78:
                    d4:e7:30:98:07:1e:de:fb:69:82:54:56:4d:7a:dc:
                    91:8b
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
            X509v3 Subject Key Identifier: 
                1A:EC:FE:4B:00:EE:C3:3D:C0:CD:BD:D8:05:9B:BC:10:61:A0:27:8E
            X509v3 Authority Key Identifier: 
                55:39:9F:AA:3D:85:10:C2:72:E4:16:0E:7A:E4:E3:9E:69:37:8C:13
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        d0:5b:40:d1:65:82:a1:13:ce:e1:b7:ab:76:f6:03:a3:e5:0c:
        b6:16:c4:d1:4f:24:81:99:99:ef:cb:e5:53:80:b3:fa:2b:fe:
        90:a7:9a:da:7a:bc:41:30:0c:fd:d2:c1:27:4c:39:15:aa:06:
        f7:f2:23:f8:2b:9c:55:47:87:48:f6:96:af:ef:5c:37:be:7d:
        60:15:48:87:41:b1:67:7f:7c:f6:66:c2:3a:3f:16:6d:59:57:
        1b:ea:63:ea:f8:74:d4:0d:bb:2a:89:a3:3c:16:57:6f:47:80:
        96:92:91:be:87:36:a9:c5:ca:00:db:55:3e:27:87:a6:fb:1b:
        b8:a1:30:fc:6a:4e:85:a9:56:45:40:4b:f4:c9:a5:99:a3:52:
        3e:e1:11:f2:0c:c3:e7:29:f0:f8:2e:14:c0:70:d0:b7:32:73:
        65:4a:40:50:5a:67:96:2b:4d:76:38:62:58:25:63:60:29:97:
        eb:d0:6d:8c:dd:0a:06:c2:9c:2d:45:d5:d1:67:51:e0:72:5a:
        e2:4f:a8:f1:6d:25:35:67:5c:c0:41:42:1e:61:86:68:e9:df:
        40:2d:c1:13:66:d0:7a:6c:33:8a:7d:1c:ac:1f:9b:3a:1a:67:
        75:51:90:ec:fb:74:af:fd:50:96:1d:9c:29:78:a2:47:29:2e:
        2b:5a:44:8e
-----BEGIN CERTIFICATE-----
MIIDwTCCAqmgAwIBAgIUBKzhzltfSFYsRZJG++3K3A7yT0cwDQYJKoZIhvcNAQEL
BQAwZDELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAlNYMQ0wCwYDVQQKDARLUkdZMQsw
CQYDVQQLDAJSRDEOMAwGA1UEAwwFTVlfQ0ExHDAaBgkqhkiG9w0BCQEWDXRlc3RA
c2luYS5jb20wHhcNMjQwMTMxMTEwMDM3WhcNMjUwMTMwMTEwMDM3WjCBgTELMAkG
A1UEBhMCQ04xCzAJBgNVBAgMAlNYMQswCQYDVQQHDAJUWTENMAsGA1UECgwES1JH
WTEUMBIGA1UECwwLc2VydmVyX2NlcnQxFTATBgNVBAMMDFNFUlZFUl9DRVJUMTEc
MBoGCSqGSIb3DQEJARYNdGVzdEBzaW5hLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAKOaZp7McwuwuO0fIIRDdI5by8/n8q7t+h9HIzlYdGQd2SgQ
M2E2o24TnEJwopA3L0roFons2VWlcAScpqIJgSW297bGXI0GyIoXg/rJhE9nbynv
UKlvz0ACzJ8uIVyZsLbSN/NCX3rssyzTEGL6MrnMlCOy+ruMA7RRWXxcOeIRaDw9
osbFMQBAyRBGR/zvDOw58swp3hNmB8qHv716Qws6kQn0feXE/QiJC3y9gWkL9hfs
+bwsI2IBsqmQuxM+hLIUVxHTBJeMO5mwPe6Z3anxoBR1IW6brgH88z+bcIkeqNWY
ip+NbZXXk24TcXB41OcwmAce3vtpglRWTXrckYsCAwEAAaNNMEswCQYDVR0TBAIw
ADAdBgNVHQ4EFgQUGuz+SwDuwz3Azb3YBZu8EGGgJ44wHwYDVR0jBBgwFoAUVTmf
qj2FEMJy5BYOeuTjnmk3jBMwDQYJKoZIhvcNAQELBQADggEBANBbQNFlgqETzuG3
q3b2A6PlDLYWxNFPJIGZme/L5VOAs/or/pCnmtp6vEEwDP3SwSdMORWqBvfyI/gr
nFVHh0j2lq/vXDe+fWAVSIdBsWd/fPZmwjo/Fm1ZVxvqY+r4dNQNuyqJozwWV29H
gJaSkb6HNqnFygDbVT4nh6b7G7ihMPxqToWpVkVAS/TJpZmjUj7hEfIMw+cp8Pgu
FMBw0Lcyc2VKQFBaZ5YrTXY4YlglY2Apl+vQbYzdCgbCnC1F1dFnUeByWuJPqPFt
JTVnXMBBQh5hhmjp30AtwRNm0HpsM4p9HKwfmzoaZ3VRkOz7dK/9UJYdnCl4okcp
LitaRI4=
-----END CERTIFICATE-----

-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFJDBWBgkqhkiG9w0BBQ0wSTAxBgkqhkiG9w0BBQwwJAQQ1u8sSfODapF0mti+
EkjAsQICCAAwDAYIKoZIhvcNAgkFADAUBggqhkiG9w0DBwQIKM05Kcht6JkEggTI
RkbSmvYL7rcuTcXKRv5A6E3a7rXIbeu2/LJNH8Y4vwtoQBrq60E85fqs/m+AlQ1P
ONUu3B8FpiJXiqMKrLy1AG8NmIeat/xyMbsY3azlPuJmb6ZJ7GAII9SbQKsytPfh
02ZiJi8ATE1VwPf3psv9G0WigrsUy7y4NvKokAnZMyOy2qOPBPt6puPxf5BcxK8g
z8tt5on4ER6gaeKkUH+/ok5pKG78ilrmel92x3AkOt+04qN6pDKvpDz3z9azunSj
k7zA1wQ6HMggl8ohuwGNmdor56funvPpYxDJZ2+DMwsf+jYxuW5G4XYkbNA2685Q
Fx9Hscw27/jaYYP506VpCe9lHnYL7xb8nyXghxLMSd480SYYgdiiPasR0NCo7ZTo
PYWVFs3Beq8c9FNUEThtaWhuVtK0MGbQEl6vCu15lO6XIlT7JUgDIgPwR27VPYVV
ncyZsPbviGBMRfEQ2DUFSbBKOXtQhIVgbf7qbf/NXMLWvZyLo/iaROCGxRQF1zrB
XdvDvKAfHzWoKMHRT58sPGuplTURsDrzwcIO1Gd5UEpYQnMpEbYXigQHPICjKmvO
OXTR7vVlpbaq8+ZMmAtJtNQ7bOxAaKN/DNBd6vd7sq7wGfAd5dE5uC797BE+yymC
NNMyK49c9WEwrVvb0GS0RnxdGtchvf/zM+h/KwfA2SlPiGUs5dprb5wZt5kGGVeX
K5ti2agnKlAoKxBwJnsIgBgUdEHYR5/k9Ovdj9JhR/a5WwgoIi/ow8OQWXH5WGCv
Gpqnc0n3XE/rrGPjLEJo+C0+yxyKqGh6vpuiV66sKGvBF3U9fzLnxhObUh/ntrb2
JxtJmRbjCcYF2lZjJ8EfJOD+7L7aONY69yTNU3DhBWtRVYq5pfGoDx94zPBQ9PJ4
OlLX7wIh0CUdnHxIeL//t6RBonVtIu6iPkCDgIXLKHjlQ+YupKORjD8h+Qoy83Ki
MQzm8rcGRwXARiYCfp1s6JQZKxjs0lVkg7IzgPDyuF7Rp17hHQv97ERRU7Hn8VI+
QGPncdnG+VVLpXDqet1PNIZFRa12D/a4gVkHdNA4IoFlzMiEfwzPEXuDov3J/Uo3
MQBKPRpCtpXLGFFeIoFRuhZUgC3+OJTHt38CFmRMphrH+DHgQ3HzIfU9+VQZZUHU
xLS1MsVZNq7XN/c7fL2yU6axiI7XwQbn01P2c26j2FWX+u82BrJ+7BrCkZ9RDkRW
kW0uGV8KrAb/22WKv5sBn2OGPajsrHBS3MqJBYi40y4xUZVmZF4XKxvYRcXtOmBW
otITMS0UGhYjFvuxffYOC557trMLz+zDyBTv99b6/ePWa5wPs5eGbsahwfDoYYN0
3sjghAbjB1LH9e+mLpA/tQ110d4PPVC2XT8hPXqBPM7392WQShRw4Rmb3h0US0iI
1NU9rbymfECZIYNoRsyD4a9jbAo+f9cbW3Y7G0mCNOjjO2VoSJb54FC+xFGTftj3
9E6xniWeM/6+A8feP3BuA2qBJ1CP3l2857Ops1MNU/clnHdgaxqnq/CP5TPcaQJ/
Fw5y/oPHo5KMZ3HNGm/PXP+w167dbfkwQFv90GkIxFg4z355JErINsYUhycUqX+7
TgJRTgKxK7Ni23H86DDpywMzFP4zovMX
-----END ENCRYPTED PRIVATE KEY-----

做实验之前, 要知道受保护的私钥的口令, 否则载入私钥会失败.

实验 pkcs12 - pkwrite.c

在VS2019中调试时, 参数为 newcert_and_key.pem pwd_my_server my_server my_server.p12

做实验的私钥newcert_and_key.pem(受密码保护)的导入口令为 pwd_my_server

c 复制代码
/*!
\file pkwrite.c
\note openssl3.2 - 官方demo学习 - pkcs12 - pkwrite.c

*/

/*
 * Copyright 2000-2023 The OpenSSL Project Authors. All Rights Reserved.
 *
 * Licensed under the Apache License 2.0 (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
 */

#include <stdio.h>
#include <stdlib.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>

#include "my_openSSL_lib.h"
#include <assert.h> // for assert()

 /* Simple PKCS#12 file creator */

// 如果要操作的PEM证书有密码, 就让密码回调函数告诉openssl操作, PEM证书的密码是啥?
int my_pem_password_cb(char* buf, int size, int rwflag, void* userdata)
{
	int i_pwd_len = 0; // 在openssl的函数中, 返回0是失败, 返回1是成功. 函数返回默认是失败
	int i_user_data = 0;

	do {
		// buf is "T"
		if (NULL == buf)
		{
			break;
		}

		if (NULL != userdata)
		{
			// 如果是面向对象变成, 这里的userdata传递的就是结构指针
			i_user_data = *((int*)userdata);
			assert(2024 == i_user_data);
		}

		// size = 1024
		// 从回调buffer入参的size可以看出, openssl中密码的最大长度为1024个字节.
		if (size < 6)
		{
			break;
		}

		// 我这个证书制作出来的时候, 密码是333333
		strcpy(buf, "333333");


		i_pwd_len = 6; // 密码"333333" 的长度为6
	} while (0);

	assert(6 == i_pwd_len);

	// 返回值为密码长度
	return i_pwd_len;
}

int main(int argc, char** argv)
{
	FILE* fp;
	EVP_PKEY* pkey;
	X509* cert;
	PKCS12* p12;

	int i_user_data = 0;

	const char* psz_infile = NULL;
	const char* psz_passwd = NULL;
	const char* psz_name = NULL;
	const char* psz_p12file = NULL;

	if (argc != 5) {
		// argv[0]  argv[1]           argv[2]  argv[3]    argv[4]
		// pkwrite  infile              pwd    name       p12file
		// this_EXE newcert_and_key.pem 333333 my_server  my_server.p12
		// 在VS2019中调试时, 参数为 newcert_and_key.pem pwd_my_server my_server  my_server.p12
		fprintf(stderr, "Usage: pkwrite infile password name p12file\n");
		exit(EXIT_FAILURE);
	}

	psz_infile = argv[1];
	psz_passwd = argv[2];
	psz_name = argv[3];
	psz_p12file = argv[4];

	OpenSSL_add_all_algorithms();
	ERR_load_crypto_strings();
	if ((fp = fopen(psz_infile, "r")) == NULL) {
		fprintf(stderr, "Error opening file %s\n", argv[1]);
		exit(EXIT_FAILURE);
	}
	cert = PEM_read_X509(fp, NULL, NULL, NULL);
	rewind(fp);

	// 如果给的就是带密码保护的证书, 调用PEM_read_PrivateKey时, 就会弹出密码输入提示
	// 得再研究一下, 不通过界面输入密码的方法
	// PEM_read_PrivateKey的参数3是密码信息的回调, 调用函数前, 传递参数3, 将密码填好再调用.
	// 我做的这个证书, 密码是333333
	// 如果PEM证书有密码, 就要提供密码信息填写的回调. my_pem_password_cb
	// 如果是面向对象编程, 就要提供用户data(参数4), 方便传递类指针, 进行面向对象变成

	i_user_data = 2024; // 用户自己的数据, openssl不用, 传啥都行, 看openssl库用户自己情况
	pkey = PEM_read_PrivateKey(fp, NULL, my_pem_password_cb, &i_user_data);
	assert(NULL != pkey);

	fclose(fp);
	p12 = PKCS12_create(psz_passwd, psz_name, pkey, cert, NULL, 0, 0, 0, 0, 0);
	if (!p12) {
		fprintf(stderr, "Error creating PKCS#12 structure\n");
		ERR_print_errors_fp(stderr);
		exit(EXIT_FAILURE);
	}
	if ((fp = fopen(psz_p12file, "wb")) == NULL) {
		fprintf(stderr, "Error opening file %s\n", psz_p12file);
		ERR_print_errors_fp(stderr);
		exit(EXIT_FAILURE);
	}
	i2d_PKCS12_fp(fp, p12);
	PKCS12_free(p12);
	fclose(fp);
	return EXIT_SUCCESS;
}

程序跑过之后, 生成了P12证书.

用win10的证书管理器安装P12证书是成功的






.P12证书受密码保护, 如果密码输入错误或不知道乱输入, 会报错, 无法导入证书.

这个口令就是产生证书时, 所谓的导出口令.




证书安装完, 可能是安装位置的缘故, 只能在管理计算机证书界面的个人/证书中看到新安装的证书.

在用户账户/管理用户证书的界面看不到新安装的证书.

打开新安装的证书后, 可以看到东西.

看证书使用者信息, 可以看到是自己签发的证书.

用官方脚本生成的证书默认是RSA2048, 如果需要其他非对加密称算法和密钥长度, 可以自己以后试试用openssl命令行来直接做.

官方脚本例子中, 有签发证书时, 选择不同的非对称加密算法和密钥长度的例子.

END

相关推荐
Lazy Dave11 天前
gmssl私钥文件格式
网络安全·ssl·openssl
沉在嵌入式的鱼1 个月前
RK3588移植Openssl库
linux·rk3588·openssl
黑屋里的马1 个月前
ssl相关命令生成证书
服务器·网络·ssl·openssl·gmssl
fangeqin1 个月前
ubuntu源码安装python3.13遇到Could not build the ssl module!解决方法
linux·python·ubuntu·openssl
API开发2 个月前
苹果芯片macOS安装版Homebrew(亲测) ,一键安装node、python、vscode等,比绿色软件还干净、无污染
vscode·python·docker·nodejs·openssl·brew·homebrew
码农不惑2 个月前
Rust使用tokio(二)HTTPS相关
https·rust·web·openssl
liulilittle2 个月前
通过高级处理器硬件指令集AES-NI实现AES-256-CFB算法并通过OPENSSL加密验证算法正确性。
linux·服务器·c++·算法·安全·加密·openssl
liulilittle2 个月前
OpenSSL 的 AES-NI 支持机制
linux·运维·服务器·算法·加密·openssl·解密
liulilittle2 个月前
通过高级处理器硬件指令集AES-NI实现AES-256-CFB算法。
linux·服务器·c++·算法·安全·加密·openssl
花花少年2 个月前
Ubuntu系统下交叉编译openssl
openssl·交叉编译