Update TLCP

This commit is contained in:
Zhi Guan
2022-06-11 23:50:54 +08:00
parent f754b1222d
commit 5eaab7033d
9 changed files with 1263 additions and 759 deletions

View File

@@ -173,7 +173,7 @@ int asn1_ia5_string_check(const char *a, size_t alen)
int asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen)
{
if (out) {
if (out && *out) {
*(*out)++ = (uint8_t)tag;
}
(*outlen)++;
@@ -183,7 +183,7 @@ int asn1_tag_to_der(int tag, uint8_t **out, size_t *outlen)
int asn1_length_to_der(size_t len, uint8_t **out, size_t *outlen)
{
if (len < 128) {
if (out) {
if (out && *out) {
*(*out)++ = (uint8_t)len;
}
(*outlen)++;
@@ -198,7 +198,7 @@ int asn1_length_to_der(size_t len, uint8_t **out, size_t *outlen)
else if (len < (1 << 24)) i = 3;
else i = 4;
if (out) {
if (out && *out) {
*(*out)++ = 0x80 + i;
memcpy(*out, buf + 4 - i, i);
(*out) += i;
@@ -211,7 +211,7 @@ int asn1_length_to_der(size_t len, uint8_t **out, size_t *outlen)
// 提供返回值是为了和其他to_der函数一致
int asn1_data_to_der(const uint8_t *data, size_t datalen, uint8_t **out, size_t *outlen)
{
if (out) {
if (out && *out) {
memcpy(*out, data, datalen);
*out += datalen;
}
@@ -301,7 +301,7 @@ int asn1_data_from_der(const uint8_t **data, size_t datalen, const uint8_t **in,
int asn1_header_to_der(int tag, size_t len, uint8_t **out, size_t *outlen)
{
if ((out && !(*out)) || !outlen) {
if (!outlen) {
error_print();
return -1;
}
@@ -429,7 +429,8 @@ int asn1_boolean_from_name(int *val, const char *name)
int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen)
{
if ((out && !(*out)) || !outlen) {
if (!outlen) {
error_print();
return -1;
}
@@ -437,7 +438,7 @@ int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen)
return 0;
}
if (out) {
if (out && *out) {
*(*out)++ = tag;
*(*out)++ = 0x01;
*(*out)++ = val ? 0xff : 0x00;
@@ -448,22 +449,20 @@ int asn1_boolean_to_der_ex(int tag, int val, uint8_t **out, size_t *outlen)
int asn1_integer_to_der_ex(int tag, const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen)
{
if (!a) {
return 0;
}
if (alen <= 0 || alen > INT_MAX || (out && !(*out)) || !outlen) {
if (!outlen) {
error_print();
return -1;
}
if (alen <= 0 || alen > INT_MAX) {
error_print();
return -1;
}
if (!a) {
return 0;
}
if (out)
if (out && *out)
*(*out)++ = tag;
(*outlen)++;
@@ -474,7 +473,7 @@ int asn1_integer_to_der_ex(int tag, const uint8_t *a, size_t alen, uint8_t **out
if (a[0] & 0x80) {
asn1_length_to_der(alen + 1, out, outlen);
if (out) {
if (out && *out) {
*(*out)++ = 0x00;
memcpy(*out, a, alen);
(*out) += alen;
@@ -482,7 +481,7 @@ int asn1_integer_to_der_ex(int tag, const uint8_t *a, size_t alen, uint8_t **out
(*outlen) += 1 + alen;
} else {
asn1_length_to_der(alen, out ,outlen);
if (out) {
if (out && *out) {
memcpy(*out, a, alen);
(*out) += alen;
}
@@ -571,11 +570,11 @@ const char *asn1_null_name(void)
int asn1_null_to_der(uint8_t **out, size_t *outlen)
{
if ((out && !(*out)) || !outlen) {
if (!outlen) {
error_print();
return -1;
}
if (out) {
if (out && *out) {
*(*out)++ = ASN1_TAG_NULL;
*(*out)++ = 0x00;
}
@@ -597,7 +596,7 @@ static void asn1_oid_node_to_base128(uint32_t a, uint8_t **out, size_t *outlen)
}
while (n--) {
if (out)
if (out && *out)
*(*out)++ = buf[n];
(*outlen)++;
}
@@ -639,10 +638,14 @@ static int asn1_oid_node_from_base128(uint32_t *a, const uint8_t **in, size_t *i
int asn1_object_identifier_to_octets(const uint32_t *nodes, size_t nodes_cnt, uint8_t *out, size_t *outlen)
{
if (!outlen) {
error_print();
return -1;
}
if (nodes_cnt < 2 || nodes_cnt > 32) {
return -1;
}
if (out)
if (out && *out)
*out++ = (uint8_t)(nodes[0] * 40 + nodes[1]);
(*outlen) = 1;
nodes += 2;
@@ -705,11 +708,12 @@ int asn1_object_identifier_to_der_ex(int tag, const uint32_t *nodes, size_t node
uint8_t octets[32];
size_t octetslen = 0;
if ((out && !(*out)) || !outlen) {
if (!outlen) {
error_print();
return -1;
}
if (out)
if (out && *out)
*(*out)++ = tag;
(*outlen)++;
@@ -717,7 +721,7 @@ int asn1_object_identifier_to_der_ex(int tag, const uint32_t *nodes, size_t node
asn1_length_to_der(octetslen, out, outlen);
if (out) {
if (out && *out) {
// 注意If out == NULL, *out ==> Segment Fault
memcpy(*out, octets, octetslen);
*out += octetslen;
@@ -824,18 +828,19 @@ int asn1_utc_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *outlen)
struct tm tm_val;
char buf[ASN1_UTC_TIME_LEN + 1];
if ((out && !(*out)) || !outlen) {
if (!outlen) {
error_print();
return -1;
}
gmtime_r(&a, &tm_val);
strftime(buf, sizeof(buf), "%y%m%d%H%M%SZ", &tm_val);
if (out)
if (out && *out)
*(*out)++ = tag;
(*outlen)++;
asn1_length_to_der(sizeof(buf)-1, out, outlen);
if (out) {
if (out && *out) {
memcpy(*out, buf, sizeof(buf)-1);
(*out) += sizeof(buf)-1;
}
@@ -850,7 +855,7 @@ int asn1_generalized_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *ou
struct tm tm_val;
char buf[ASN1_GENERALIZED_TIME_LEN + 1];
if ((out && !(*out)) || !outlen) {
if (!outlen) {
error_print();
return -1;
}
@@ -859,11 +864,11 @@ int asn1_generalized_time_to_der_ex(int tag, time_t a, uint8_t **out, size_t *ou
strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &tm_val);
//printf("%s %d: generalized time : %s\n", __FILE__, __LINE__, buf);
if (out)
if (out && *out)
*(*out)++ = tag;
(*outlen)++;
asn1_length_to_der(ASN1_GENERALIZED_TIME_LEN, out, outlen);
if (out) {
if (out && *out) {
memcpy(*out, buf, ASN1_GENERALIZED_TIME_LEN);
(*out) += ASN1_GENERALIZED_TIME_LEN;
}

View File

@@ -159,11 +159,10 @@ int tlcp_server_key_exchange_pke_print(FILE *fp, const uint8_t *data, size_t dat
return 1;
}
int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
FILE *ca_certs_fp, FILE *client_certs_fp, const SM2_KEY *client_sign_key)
int tlcp_do_connect(TLS_CONNECT *conn)
{
int ret = -1;
uint8_t record[TLS_MAX_RECORD_SIZE];
uint8_t *record = conn->record;
uint8_t finished_record[TLS_FINISHED_RECORD_BUF_SIZE];
size_t recordlen, finished_record_len;
@@ -205,29 +204,6 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
int alert = 0;
int verify_result;
struct sockaddr_in server;
memset(conn, 0, sizeof(*conn));
conn->is_client = 1;
// 设置CA证书和客户端证书
if (ca_certs_fp) {
if (x509_certs_from_pem(conn->ca_certs, &conn->ca_certs_len, 2048, ca_certs_fp) != 1) {
error_print();
goto end;
}
}
if (client_sign_key) {
if (!client_certs_fp) {
error_print();
goto end;
}
if (x509_certs_from_pem(conn->client_certs, &conn->client_certs_len, 2048, client_certs_fp) != 1) {
error_print();
goto end;
}
}
// 初始化记录缓冲
tls_record_set_version(record, TLS_version_tlcp);
@@ -235,21 +211,8 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
// 准备Finished Context和ClientVerify
sm3_init(&sm3_ctx);
if (client_sign_key)
sm2_sign_init(&sign_ctx, client_sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH);
// 设置Socket
server.sin_addr.s_addr = inet_addr(hostname);
server.sin_family = AF_INET;
server.sin_port = htons(port);
if ((conn->sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
error_print();
goto end;
}
if (connect(conn->sock, (struct sockaddr *)&server , sizeof(server)) < 0) {
error_print();
goto end;
}
if (conn->client_certs_len)
sm2_sign_init(&sign_ctx, &conn->sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH);
// send ClientHello
@@ -267,7 +230,7 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
goto end;
}
sm3_update(&sm3_ctx, record + 5, recordlen - 5);
if (client_sign_key)
if (conn->client_certs_len)
sm2_sign_update(&sign_ctx, record + 5, recordlen - 5);
// recv ServerHello
@@ -309,7 +272,7 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
memcpy(conn->session_id, session_id, session_id_len);
conn->cipher_suite = cipher_suite;
sm3_update(&sm3_ctx, record + 5, recordlen - 5);
if (client_sign_key)
if (conn->client_certs_len)
sm2_sign_update(&sign_ctx, record + 5, recordlen - 5);
// recv ServerCertificate
@@ -321,6 +284,7 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
goto end;
}
tlcp_record_trace(stderr, record, recordlen, 0, 0);
if (tls_record_get_handshake_certificate(record,
conn->server_certs, &conn->server_certs_len) != 1) {
error_print();
@@ -328,7 +292,7 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
goto end;
}
sm3_update(&sm3_ctx, record + 5, recordlen - 5);
if (client_sign_key)
if (conn->client_certs_len)
sm2_sign_update(&sign_ctx, record + 5, recordlen - 5);
// verify ServerCertificate
@@ -354,7 +318,7 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
goto end;
}
sm3_update(&sm3_ctx, record + 5, recordlen - 5);
if (client_sign_key)
if (conn->client_certs_len)
sm2_sign_update(&sign_ctx, record + 5, recordlen - 5);
// verify ServerKeyExchange
@@ -406,7 +370,7 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
if(!client_sign_key) {
if(!conn->client_certs_len) {
error_print();
tls_send_alert(conn, TLS_alert_internal_error);
goto end;
@@ -428,7 +392,10 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
goto end;
}
} else {
client_sign_key = NULL;
// 这个得处理一下
conn->client_certs_len = 0;
gmssl_secure_clear(&conn->sign_key, sizeof(SM2_KEY));
//client_sign_key = NULL;
}
tls_trace("recv ServerHelloDone\n");
tlcp_record_trace(stderr, record, recordlen, 0, 0);
@@ -438,11 +405,11 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
goto end;
}
sm3_update(&sm3_ctx, record + 5, recordlen - 5);
if (client_sign_key)
if (conn->client_certs_len)
sm2_sign_update(&sign_ctx, record + 5, recordlen - 5);
// send ClientCertificate
if (client_sign_key) {
if (conn->client_certs_len) {
tls_trace("send ClientCertificate\n");
if (tls_record_set_handshake_certificate(record, &recordlen, conn->client_certs, conn->client_certs_len) != 1) {
error_print();
@@ -475,15 +442,12 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32);
sm4_set_encrypt_key(&conn->client_write_enc_key, conn->key_block + 64);
sm4_set_decrypt_key(&conn->server_write_enc_key, conn->key_block + 80);
/*
format_bytes(stderr, 0, 4, "PRE_MASTER_SECRET", pre_master_secret, 48);
format_bytes(stderr, 0, 4, "MASTER_SECRET", conn->master_secret, 48);
format_bytes(stderr, 0, 4, "CLIENT_WRITE_MAC_KEY", conn->key_block, 32);
format_bytes(stderr, 0, 4, "SERVER_WRITE_MAC_KEY", conn->key_block + 32, 32);
format_bytes(stderr, 0, 4, "CLIENT_WRITE_ENC_KEY", conn->key_block + 64, 16);
format_bytes(stderr, 0, 4, "SERVER_WRITE_ENC_KEY", conn->key_block + 80, 16);
format_print(stderr, 0, 0, "\n");
*/
tls_secrets_print(stderr,
pre_master_secret, 48,
client_random, server_random,
conn->master_secret,
conn->key_block, 96,
0, 4);
// send ClientKeyExchange
tls_trace("send ClientKeyExchange\n");
@@ -501,11 +465,11 @@ int tlcp_connect(TLS_CONNECT *conn, const char *hostname, int port,
goto end;
}
sm3_update(&sm3_ctx, record + 5, recordlen - 5);
if (client_sign_key)
if (conn->client_certs_len)
sm2_sign_update(&sign_ctx, record + 5, recordlen - 5);
// send CertificateVerify
if (client_sign_key) {
if (conn->client_certs_len) {
tls_trace("send CertificateVerify\n");
uint8_t sigbuf[SM2_MAX_SIGNATURE_SIZE];
if (sm2_sign_finish(&sign_ctx, sigbuf, &siglen) != 1
@@ -639,21 +603,13 @@ end:
return 1;
}
int tlcp_accept(TLS_CONNECT *conn, int port,
FILE *certs_fp, const SM2_KEY *server_sign_key, const SM2_KEY *server_enc_key,
FILE *client_cacerts_fp, uint8_t *handshakes_buf, size_t handshakes_buflen)
int tlcp_do_accept(TLS_CONNECT *conn)
{
int ret = -1;
int sock;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
socklen_t client_addrlen;
int client_verify = 0;
uint8_t record[TLS_MAX_RECORD_SIZE];
uint8_t *record = conn->record;
uint8_t finished_record[TLS_FINISHED_RECORD_BUF_SIZE]; // 解密可能导致前面的record被覆盖
size_t recordlen, finished_record_len;
const int server_ciphers[] = { TLCP_cipher_ecc_sm4_cbc_sm3 }; // 未来应该支持GCM/CBC两个套件
@@ -704,51 +660,9 @@ int tlcp_accept(TLS_CONNECT *conn, int port,
size_t len;
memset(conn, 0, sizeof(*conn));
// 设置服务器证书客户端验证CA证书
if (!certs_fp || !server_sign_key || !server_enc_key) {
error_print();
goto end;
}
if (x509_certs_from_pem(conn->server_certs, &conn->server_certs_len, 2048, certs_fp) != 1) {
error_print();
goto end;
}
if (client_cacerts_fp) {
if (x509_certs_from_pem(conn->ca_certs, &conn->ca_certs_len, 2048, client_cacerts_fp) != 1) {
error_print();
goto end;
}
// 服务器端如果设置了CA
if (conn->ca_certs_len)
client_verify = 1;
}
// Socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
error_print();
goto end;
}
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
error_print();
perror("tlcp_accept: bind: ");
goto end;
}
puts("start listen ...\n");
listen(sock, 5);
client_addrlen = sizeof(client_addr);
if ((conn->sock = accept(sock, (struct sockaddr *)&client_addr, &client_addrlen)) < 0) {
error_print();
goto end;
}
puts("socket connected\n");
// 初始化Finished和客户端验证环境
sm3_init(&sm3_ctx);
@@ -846,7 +760,7 @@ int tlcp_accept(TLS_CONNECT *conn, int port,
}
p = server_enc_cert_lenbuf; len = 0;
tls_uint24_to_bytes(server_enc_cert_len, &p, &len);
if (sm2_sign_init(&sign_ctx, server_sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
if (sm2_sign_init(&sign_ctx, &conn->sign_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1
|| sm2_sign_update(&sign_ctx, client_random, 32) != 1
|| sm2_sign_update(&sign_ctx, server_random, 32) != 1
|| sm2_sign_update(&sign_ctx, server_enc_cert_lenbuf, 3) != 1
@@ -910,7 +824,7 @@ int tlcp_accept(TLS_CONNECT *conn, int port,
tls_client_verify_update(&client_verify_ctx, record + 5, recordlen - 5);
// recv ClientCertificate
if (client_cacerts_fp) {
if (conn->ca_certs_len) {
tls_trace("recv ClientCertificate\n");
if (tls_record_recv(record, &recordlen, conn->sock) != 1
|| tls_record_version(record) != TLS_version_tlcp) {
@@ -948,7 +862,7 @@ int tlcp_accept(TLS_CONNECT *conn, int port,
tls_send_alert(conn, TLS_alert_unexpected_message);
goto end;
}
if (sm2_decrypt(server_enc_key, enced_pms, enced_pms_len,
if (sm2_decrypt(&conn->kenc_key, enced_pms, enced_pms_len,
pre_master_secret, &pre_master_secret_len) != 1) {
error_print();
tls_send_alert(conn, TLS_alert_decrypt_error);
@@ -1008,15 +922,12 @@ int tlcp_accept(TLS_CONNECT *conn, int port,
sm3_hmac_init(&conn->server_write_mac_ctx, conn->key_block + 32, 32);
sm4_set_decrypt_key(&conn->client_write_enc_key, conn->key_block + 64);
sm4_set_encrypt_key(&conn->server_write_enc_key, conn->key_block + 80);
/*
format_bytes(stderr, 0, 4, "PRE_MASTER_SECRET", pre_master_secret, 48);
format_bytes(stderr, 0, 4, "MASTER_SECRET", conn->master_secret, 48);
format_bytes(stderr, 0, 4, "CLIENT_WRITE_MAC_KEY", conn->key_block, 32);
format_bytes(stderr, 0, 4, "SERVER_WRITE_MAC_KEY", conn->key_block + 32, 32);
format_bytes(stderr, 0, 4, "CLIENT_WRITE_ENC_KEY", conn->key_block + 64, 16);
format_bytes(stderr, 0, 4, "SERVER_WRITE_ENC_KEY", conn->key_block + 80, 16);
format_print(stderr, 0, 0, "\n");
*/
tls_secrets_print(stderr,
pre_master_secret, 48,
client_random, server_random,
conn->master_secret,
conn->key_block, 96,
0, 4);
// recv [ChangeCipherSpec]
tls_trace("recv [ChangeCipherSpec]\n");

1124
src/tls.c

File diff suppressed because it is too large Load Diff

View File

@@ -899,6 +899,7 @@ int tls_application_data_print(FILE *fp, const uint8_t *data, size_t datalen, in
// 当消息为ClientKeyExchange,ServerKeyExchange需要密码套件中的密钥交换算法信息
// 当消息为加密的Finished记录类型为Handshake但是记录负载数据中没有Handshake头
// 注意这里的recordlen 是冗余的要容忍recordlen的错误
int tls_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int format, int indent)
{
const uint8_t *data;
@@ -913,10 +914,15 @@ int tls_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int for
format_print(fp, format, indent, "Record\n"); indent += 4;
format_print(fp, format, indent, "ContentType: %s (%d)\n", tls_record_type_name(record[0]), record[0]);
format_print(fp, format, indent, "Version: %s (%d.%d)\n", tls_version_text(version), version >> 8, version & 0xff);
format_print(fp, format, indent, "Length: %d\n", tls_record_length(record));
format_print(fp, format, indent, "Length: %d\n", tls_record_data_length(record));
data = record + 5;
datalen = recordlen - 5;
data = tls_record_data(record);
datalen = tls_record_data_length(record);
if (recordlen < tls_record_length(record)) {
error_print();
return -1;
}
// 最高字节设置后强制打印记录原始数据
if (format >> 24) {
@@ -954,6 +960,12 @@ int tls_record_print(FILE *fp, const uint8_t *record, size_t recordlen, int for
error_print();
return -1;
}
recordlen -= tls_record_length(record);
if (recordlen) {
format_print(fp, 0, 0, "DataLeftInRecord: %zu\n", recordlen);
}
fprintf(fp, "\n");
return 1;
}
@@ -965,6 +977,7 @@ int tls_secrets_print(FILE *fp,
const uint8_t *key_block, size_t key_block_len,
int format, int indent)
{
// 应该检查一下key_block_len的值判断是否支持或者算法选择, 或者要求输入一个cipher_suite参数
format_bytes(stderr, format, indent, "pre_master_secret", pre_master_secret, pre_master_secret_len);
format_bytes(stderr, format, indent, "client_random", client_random, 32);
format_bytes(stderr, format, indent, "server_random", server_random, 32);

View File

@@ -1016,6 +1016,9 @@ int x509_certificate_print(FILE *fp, int fmt, int ind, const char *label, const
size_t len;
int val;
format_print(fp, fmt, ind, "%s\n", label);
ind += 4;
if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) goto err;
x509_tbs_cert_print(fp, fmt, ind, "tbsCertificate", p, len);
if (x509_signature_algor_from_der(&val, &d, &dlen) != 1) goto err;
@@ -1640,3 +1643,65 @@ int x509_certs_print(FILE *fp, int fmt, int ind, const char *label, const uint8_
}
return 1;
}
#include <errno.h>
#include <sys/stat.h>
int x509_cert_new_from_file(uint8_t **out, size_t *outlen, const char *file)
{
int ret = -1;
FILE *fp = NULL;
struct stat st;
uint8_t *buf = NULL;
size_t buflen;
if (!(fp = fopen(file, "r"))
|| fstat(fileno(fp), &st) < 0
|| (buflen = (st.st_size * 3)/4 + 1) < 0
|| (buf = malloc((st.st_size * 3)/4 + 1)) == NULL) {
error_print();
goto end;
}
if (x509_cert_from_pem(buf, outlen, buflen, fp) != 1) {
error_print();
goto end;
}
*out = buf;
buf = NULL;
ret = 1;
end:
if (fp) fclose(fp);
if (buf) free(buf);
return ret;
}
int x509_certs_new_from_file(uint8_t **out, size_t *outlen, const char *file)
{
int ret = -1;
FILE *fp = NULL;
struct stat st;
uint8_t *buf = NULL;
size_t buflen;
if (!(fp = fopen(file, "r"))
|| fstat(fileno(fp), &st) < 0
|| (buflen = (st.st_size * 3)/4 + 1) < 0
|| (buf = malloc((st.st_size * 3)/4 + 1)) == NULL) {
error_print();
goto end;
}
if (x509_certs_from_pem(buf, outlen, buflen, fp) != 1) {
error_print();
goto end;
}
*out = buf;
buf = NULL;
ret = 1;
end:
if (fp) fclose(fp);
if (buf) free(buf);
return ret;
}