From 767dae98ab6930143c4de5f627f262d649f12aff Mon Sep 17 00:00:00 2001 From: Zhi Guan Date: Thu, 26 May 2022 23:57:32 +0800 Subject: [PATCH] Update Tools --- demos/certdemo.sh | 14 ++ demos/cmsdemo.sh | 17 +++ demos/reqdemo.sh | 19 +++ demos/sm234demo.sh | 16 +++ include/gmssl/cms.h | 7 + include/gmssl/digest.h | 4 +- include/gmssl/oid.h | 2 + include/gmssl/sm2.h | 4 + include/gmssl/x509.h | 14 +- include/gmssl/x509_alg.h | 1 + include/gmssl/x509_crl.h | 4 + include/gmssl/x509_ext.h | 18 +++ src/asn1.c | 20 +-- src/cms.c | 259 +++++++++++++++++++++++++++---------- src/digest.c | 8 +- src/pem.c | 4 + src/sm2_alg.c | 6 - src/sm2_lib.c | 73 ++++++++--- src/x509_alg.c | 28 ++-- src/x509_cer.c | 147 +++++++++++++++++---- src/x509_crl.c | 73 +++++++++-- src/x509_ext.c | 52 ++++++-- src/x509_oid.c | 4 + tests/digesttest.c | 2 +- tools/certgen.c | 125 +++++++++--------- tools/certparse.c | 60 +++++---- tools/certverify.c | 100 ++++++++------- tools/cmsdecrypt.c | 215 +++++++++++++++++++++++++++++++ tools/cmsencrypt.c | 270 +++++++++++++++++++++++++++++++++++++++ tools/cmsparse.c | 126 ++++++++++++++++++ tools/cmssign.c | 246 +++++++++++++++++++++++++++++++++++ tools/cmsverify.c | 177 +++++++++++++++++++++++++ tools/crlparse.c | 64 ++++++---- tools/gmssl.c | 52 +++++--- tools/reqgen.c | 128 ++++++++++--------- tools/reqparse.c | 59 +++++---- tools/reqsign.c | 173 +++++++++++++------------ tools/sm2decrypt.c | 4 +- 38 files changed, 2090 insertions(+), 505 deletions(-) create mode 100755 demos/certdemo.sh create mode 100755 demos/cmsdemo.sh create mode 100755 demos/reqdemo.sh create mode 100755 demos/sm234demo.sh create mode 100644 tools/cmsdecrypt.c create mode 100644 tools/cmsencrypt.c create mode 100644 tools/cmsparse.c create mode 100644 tools/cmssign.c create mode 100644 tools/cmsverify.c diff --git a/demos/certdemo.sh b/demos/certdemo.sh new file mode 100755 index 00000000..4ea3f849 --- /dev/null +++ b/demos/certdemo.sh @@ -0,0 +1,14 @@ +#!/bin/bash -x + +# generate sm2 keypair and encrypt with password +gmssl sm2keygen -pass 1234 -out sm2.pem -pubout sm2pub.pem + +# generate a self-signed certificate +gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN Alice -days 365 -key sm2.pem -pass 1234 \ + -key_usage "digitalSignature" -key_usage "keyCertSign" -key_usage cRLSign \ + -out cert.pem + +gmssl certparse -in cert.pem + + + diff --git a/demos/cmsdemo.sh b/demos/cmsdemo.sh new file mode 100755 index 00000000..e4ec19e8 --- /dev/null +++ b/demos/cmsdemo.sh @@ -0,0 +1,17 @@ +#!/bin/bash + + +gmssl sm2keygen -pass 1234 -out key.pem -pubout keypub.pem +gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN Alice -days 365 -key key.pem -pass 1234 -out cert.pem + +echo "The plaintext message." > plain.txt + +gmssl cmsencrypt -in plain.txt -rcptcert cert.pem -out enveloped_data.pem +gmssl cmsparse -in enveloped_data.pem +gmssl cmsdecrypt -key key.pem -pass 1234 -cert cert.pem -in enveloped_data.pem + +gmssl cmssign -key key.pem -pass 1234 -cert cert.pem -in plain.txt -out signed_data.pem +gmssl cmsparse -in signed_data.pem +gmssl cmsverify -in signed_data.pem -out signed_data.txt +cat signed_data.txt + diff --git a/demos/reqdemo.sh b/demos/reqdemo.sh new file mode 100755 index 00000000..3b8217a2 --- /dev/null +++ b/demos/reqdemo.sh @@ -0,0 +1,19 @@ +#!/bin/bash -x + +# generate self-signed CA certificate +gmssl sm2keygen -pass 1234 -out cakey.pem -pubout pubkey.pem +gmssl certgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN CA -days 365 -key cakey.pem -pass 1234 -out cacert.pem +gmssl certparse -in cacert.pem + +# generate a req and sign by CA certificate +gmssl sm2keygen -pass 1234 -out signkey.pem -pubout pubkey.pem +gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN Alice -days 365 -key signkey.pem -pass 1234 -out signreq.pem +gmssl reqsign -in signreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out signcert.pem +gmssl certparse -in signcert.pem + +# sign a encryption certificate with the same DN, different KeyUsage extension +gmssl sm2keygen -pass 1234 -out enckey.pem -pubout pubkey.pem +gmssl reqgen -C CN -ST Beijing -L Haidian -O PKU -OU CS -CN Alice -days 365 -key enckey.pem -pass 1234 -out encreq.pem +gmssl reqsign -in encreq.pem -days 365 -key_usage digitalSignature -cacert cacert.pem -key cakey.pem -pass 1234 -out enccert.pem +gmssl certparse -in enccert.pem + diff --git a/demos/sm234demo.sh b/demos/sm234demo.sh new file mode 100755 index 00000000..786d6160 --- /dev/null +++ b/demos/sm234demo.sh @@ -0,0 +1,16 @@ +#!/bin/bash + + +ENC_KEY=`gmssl rand -outlen 16 -hex` +MAC_KEY=`gmssl rand -outlen 32 -hex` +IV=`gmssl rand -outlen 16 -hex` + +gmssl sm2keygen -pass 1234 -out sm2.pem -pubout sm2pub.pem + +echo "$ENC_KEY$MAC_KEY" | xxd -p -r | gmssl sm2encrypt -pubkey sm2pub.pem | xxd -p > out.bin +echo $IV >> out.bin +echo "plaintext" | gmssl sm4 -cbc -encrypt -key $ENC_KEY -iv $IV | xxd -p >> out.bin + + +# gmssl sm2decrypt -key sm2.pem -pass 1234 -in sm2.der + diff --git a/include/gmssl/cms.h b/include/gmssl/cms.h index a3662e33..91b0c091 100644 --- a/include/gmssl/cms.h +++ b/include/gmssl/cms.h @@ -327,6 +327,8 @@ RecipientInfo ::= SEQUENCE { keyEncryptionAlgorithm AlgorithmIdentifier, encryptedKey OCTET STRING -- DER-encoding of SM2Cipher } +由于encryptedKey的类型为SM2Cipher, 而SM2Cipher中有2个INTEGER,因此长度是不固定的。 +因此不能预先确定输出长度 */ int cms_recipient_info_to_der( int version, @@ -574,6 +576,11 @@ int cms_set_key_agreement_info( const uint8_t *user_cert, size_t user_cert_len, const uint8_t *user_id, size_t user_id_len); +#define PEM_CMS "CMS" +int cms_to_pem(const uint8_t *cms, size_t cms_len, FILE *fp); +int cms_from_pem(uint8_t *cms, size_t *cms_len, size_t maxlen, FILE *fp); + + int cms_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen); diff --git a/include/gmssl/digest.h b/include/gmssl/digest.h index 92695fd6..9447f2b4 100644 --- a/include/gmssl/digest.h +++ b/include/gmssl/digest.h @@ -75,7 +75,7 @@ typedef struct DIGEST_CTX DIGEST_CTX; struct DIGEST_CTX { union { SM3_CTX sm3_ctx; - MD5_CTX md5_ctx; +// MD5_CTX md5_ctx; SHA1_CTX sha1_ctx; SHA224_CTX sha224_ctx; SHA256_CTX sha256_ctx; @@ -96,7 +96,7 @@ struct DIGEST { }; const DIGEST *DIGEST_sm3(void); -const DIGEST *DIGEST_md5(void); +//const DIGEST *DIGEST_md5(void); const DIGEST *DIGEST_sha1(void); const DIGEST *DIGEST_sha224(void); const DIGEST *DIGEST_sha256(void); diff --git a/include/gmssl/oid.h b/include/gmssl/oid.h index 69c5cce8..842e9f03 100644 --- a/include/gmssl/oid.h +++ b/include/gmssl/oid.h @@ -103,6 +103,7 @@ enum { OID_at_serial_number, OID_at_pseudonym, OID_domain_component, + OID_email_address, // Cert Extensions OID_ce_authority_key_identifier, @@ -120,6 +121,7 @@ enum { OID_ce_crl_distribution_points, OID_ce_inhibit_any_policy, OID_ce_freshest_crl, + OID_netscape_cert_type, OID_netscape_cert_comment, OID_cert_authority_info_access, OID_ct_precertificate_scts, diff --git a/include/gmssl/sm2.h b/include/gmssl/sm2.h index fa78ac2f..e3d175f6 100644 --- a/include/gmssl/sm2.h +++ b/include/gmssl/sm2.h @@ -336,6 +336,7 @@ typedef struct { uint8_t s[32]; } SM2_SIGNATURE; +int sm2_do_sign_ex(const SM2_KEY *key, int flags, const uint8_t dgst[32], SM2_SIGNATURE *sig); int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig); int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig); @@ -344,6 +345,7 @@ int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATUR int sm2_signature_to_der(const SM2_SIGNATURE *sig, uint8_t **out, size_t *outlen); int sm2_signature_from_der(SM2_SIGNATURE *sig, const uint8_t **in, size_t *inlen); int sm2_signature_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *sig, size_t siglen); +int sm2_sign_ex(const SM2_KEY *key, int flags, const uint8_t dgst[32], uint8_t *sig, size_t *siglen); int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen); int sm2_verify(const SM2_KEY *key, const uint8_t dgst[32], const uint8_t *sig, size_t siglen); @@ -387,6 +389,7 @@ typedef struct { uint8_t ciphertext[SM2_MAX_PLAINTEXT_SIZE]; } SM2_CIPHERTEXT; +int sm2_do_encrypt_ex(const SM2_KEY *key, int flags, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out); int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out); int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen); @@ -395,6 +398,7 @@ int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, s int sm2_ciphertext_to_der(const SM2_CIPHERTEXT *c, uint8_t **out, size_t *outlen); int sm2_ciphertext_from_der(SM2_CIPHERTEXT *c, const uint8_t **in, size_t *inlen); int sm2_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen); +int sm2_encrypt_ex(const SM2_KEY *key, int flags, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); int sm2_decrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen); diff --git a/include/gmssl/x509.h b/include/gmssl/x509.h index 72e83816..2cdbe45e 100644 --- a/include/gmssl/x509.h +++ b/include/gmssl/x509.h @@ -76,7 +76,6 @@ X509 Public API x509_name_to_der x509_name_from_der x509_name_print - x509_name_get_printable x509_name_get_value_by_type x509_name_get_common_name @@ -171,6 +170,16 @@ int x509_rdn_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t /* Name ::= SEQUENCE OF RelativeDistinguishedName + +Example: + SEQUENCE LEN + SET LEN + SEQUENCE LEN OID=countryName, String=CN + SET LEN + SEQUENCE LEN OID=stateName, String=CN + SEQUENCE LEN OID=unknown, String=ABC + SET LEN + SEQUENCE LEN OID=commonNmame, String=ABC */ int x509_name_add_rdn(uint8_t *d, size_t *dlen, size_t maxlen, int oid, int tag, const uint8_t *val, size_t vlen, const uint8_t *more, size_t mlen); int x509_name_add_country_name(uint8_t *d, size_t *dlen, int maxlen, const char val[2] ); // val: PrintableString SIZE(2) @@ -188,7 +197,6 @@ int x509_name_set(uint8_t *d, size_t *dlen, size_t maxlen, #define x509_name_to_der(d,dlen,out,outlen) asn1_sequence_to_der(d,dlen,out,outlen) #define x509_name_from_der(d,dlen,in,inlen) asn1_sequence_from_der(d,dlen,in,inlen) int x509_name_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen); -int x509_name_get_printable(const uint8_t *d, size_t dlen, char *str, size_t maxlen); int x509_name_get_value_by_type(const uint8_t *d, size_t dlen, int oid, int *tag, const uint8_t **val, size_t *vlen); int x509_name_get_common_name(const uint8_t *d, size_t dlen, int *tag, const uint8_t **val, size_t *vlen); @@ -348,7 +356,7 @@ int x509_cert_get_subject(const uint8_t *a, size_t alen, const uint8_t **subj, s int x509_cert_get_subject_public_key(const uint8_t *a, size_t alen, SM2_KEY *public_key); int x509_certs_to_pem(const uint8_t *d, size_t dlen, FILE *fp); -int x509_certs_from_pem(const uint8_t *d, size_t *dlen, size_t maxlen, FILE *fp); +int x509_certs_from_pem(uint8_t *d, size_t *dlen, size_t maxlen, FILE *fp); int x509_certs_get_count(const uint8_t *d, size_t dlen, size_t *cnt); int x509_certs_get_cert_by_index(const uint8_t *d, size_t dlen, int index, const uint8_t **cert, size_t *certlen); int x509_certs_get_cert_by_subject(const uint8_t *d, size_t dlen, const uint8_t *subject, size_t subject_len, const uint8_t **cert, size_t *certlen); diff --git a/include/gmssl/x509_alg.h b/include/gmssl/x509_alg.h index 7095659f..0b8e855f 100644 --- a/include/gmssl/x509_alg.h +++ b/include/gmssl/x509_alg.h @@ -80,6 +80,7 @@ int x509_encryption_algor_from_der(int *oid, const uint8_t **iv, size_t *ivlen, int x509_encryption_algor_to_der(int oid, const uint8_t *iv, size_t ivlen, uint8_t **out, size_t *outlen); int x509_encryption_algor_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *d, size_t dlen); +#define X509_ALGOR_ALLOW_EC_NULL_PARAM 1 const char *x509_signature_algor_name(int oid); int x509_signature_algor_from_name(const char *name); int x509_signature_algor_from_der(int *oid, const uint8_t **in, size_t *inlen); diff --git a/include/gmssl/x509_crl.h b/include/gmssl/x509_crl.h index b0231316..75eb6d64 100644 --- a/include/gmssl/x509_crl.h +++ b/include/gmssl/x509_crl.h @@ -268,6 +268,10 @@ int x509_crl_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen int x509_crl_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen); int x509_crl_to_pem(const uint8_t *a, size_t alen, FILE *fp); int x509_crl_from_pem(uint8_t *a, size_t *alen, size_t maxlen, FILE *fp); +int x509_crl_to_fp(const uint8_t *a, size_t alen, FILE *fp); +int x509_crl_from_fp(uint8_t *a, size_t *alen, size_t maxlen, FILE *fp); + + int x509_crl_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen); int x509_crl_sign(uint8_t *crl, size_t *crl_len, diff --git a/include/gmssl/x509_ext.h b/include/gmssl/x509_ext.h index c0efd1db..934afba9 100644 --- a/include/gmssl/x509_ext.h +++ b/include/gmssl/x509_ext.h @@ -554,6 +554,24 @@ FreshestCRL ::= CRLDistributionPoints #define x509_freshest_crl_from_der(d,dlen,in,inlen) x509_crl_distribution_points_from_der(d,dlen,in,inlen) #define x509_freshest_crl_print(fp,fmt,ind,label,d,dlen) x509_crl_distribution_points_print(fp,fmt,ind,label,d,dlen) +/* +Netscape-Defined Certificate Extensions +https://docs.oracle.com/cd/E19957-01/816-5533-10/ext.htm#1023061 + +NetscapeCertType ::= BIT STRING + + bit 0: SSL Client certificate + bit 1: SSL Server certificate + bit 2: S/MIME certificate + bit 3: Object-signing certificate + bit 4: Reserved for future use + bit 5: SSL CA certificate + bit 6: S/MIME CA certificate + bit 7: Object-signing CA certificate + +NetscapeCertComment ::= IA5String +*/ +int x509_netscape_cert_type_print(FILE *fp, int fmt, int ind, const char *label, int bits); #ifdef __cplusplus } diff --git a/src/asn1.c b/src/asn1.c index 4fe0dc2f..de4980d3 100644 --- a/src/asn1.c +++ b/src/asn1.c @@ -738,6 +738,7 @@ const ASN1_OID_INFO *asn1_oid_info_from_oid(const ASN1_OID_INFO *infos, size_t c return NULL; } +// 如果一个正确解析的OID并不在infos列表中,那么仍然返回1,但是调用方必须检查返回的info是否为空 int asn1_oid_info_from_der_ex(const ASN1_OID_INFO **info, uint32_t *nodes, size_t *nodes_cnt, const ASN1_OID_INFO *infos, size_t count, const uint8_t **in, size_t *inlen) { @@ -753,27 +754,30 @@ int asn1_oid_info_from_der_ex(const ASN1_OID_INFO **info, uint32_t *nodes, size_ if (*nodes_cnt == infos[i].nodes_cnt && memcmp(nodes, infos[i].nodes, (*nodes_cnt) * sizeof(int)) == 0) { *info = &infos[i]; - return 1; + goto end; } } - // 注意,此时虽然返回1,但是*info == NULL,因此调用方应该显式的判断info +end: return 1; } +// 和ex版本不同的是,如果在infos列表中未找到OID,返回错误 int asn1_oid_info_from_der(const ASN1_OID_INFO **info, const ASN1_OID_INFO *infos, size_t count, const uint8_t **in, size_t *inlen) { int ret; uint32_t nodes[32]; size_t nodes_cnt; - if ((ret = asn1_oid_info_from_der_ex(info, nodes, &nodes_cnt, infos, count, in, inlen)) < 0) { - error_print(); - return -1; - } else if (ret > 1) { + if ((ret = asn1_oid_info_from_der_ex(info, nodes, &nodes_cnt, infos, count, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + if (*info == NULL) { + asn1_object_identifier_print(stderr, 0, 0, "Unknown OID", NULL, nodes, nodes_cnt); error_print(); return -1; } - return ret; + return 1; } @@ -1355,7 +1359,7 @@ int asn1_object_identifier_print(FILE *fp, int format, int indent, const char *l const uint32_t *nodes, size_t nodes_cnt) { size_t i; - format_print(fp, format, indent, "%s: %s", label, name); + format_print(fp, format, indent, "%s: %s", label, name ? name : "(unknown)"); if (nodes) { fprintf(fp, " ("); for (i = 0; i < nodes_cnt - 1; i++) { diff --git a/src/cms.c b/src/cms.c index 4c4314c7..9ff9e25b 100644 --- a/src/cms.c +++ b/src/cms.c @@ -63,6 +63,7 @@ #include #include #include +#include #include @@ -110,14 +111,15 @@ int cms_content_type_from_name(const char *name) int cms_content_type_to_der(int oid, uint8_t **out, size_t *outlen) { const ASN1_OID_INFO *info; - size_t len = 0; + + if (oid == -1) { + return 0; + } if (!(info = asn1_oid_info_from_oid(cms_content_types, cms_content_types_count, oid))) { error_print(); return -1; } - if (asn1_object_identifier_to_der(info->nodes, info->nodes_cnt, NULL, &len) != 1 - || asn1_sequence_header_to_der(len, out, outlen) != 1 - || asn1_object_identifier_to_der(info->nodes, info->nodes_cnt, out, outlen) != 1) { + if (asn1_object_identifier_to_der(info->nodes, info->nodes_cnt, out, outlen) != 1) { error_print(); return -1; } @@ -127,18 +129,11 @@ int cms_content_type_to_der(int oid, uint8_t **out, size_t *outlen) int cms_content_type_from_der(int *oid, const uint8_t **in, size_t *inlen) { int ret; - const uint8_t *p; - size_t len; const ASN1_OID_INFO *info; - *oid = 0; - if ((ret = asn1_sequence_from_der(&p, &len, in, inlen)) != 1) { + if ((ret = asn1_oid_info_from_der(&info, cms_content_types, cms_content_types_count, in, inlen)) != 1) { if (ret < 0) error_print(); - return ret; - } - if ((ret = asn1_oid_info_from_der(&info, cms_content_types, cms_content_types_count, &p, &len)) != 1 - || asn1_length_is_zero(len) != 1) { - error_print(); + else *oid = -1; return ret; } *oid = info->oid; @@ -164,12 +159,13 @@ static int cms_content_info_data_header_to_der(size_t dlen, uint8_t **out, size_ int cms_content_info_header_to_der(int content_type, size_t content_len, uint8_t **out, size_t *outlen) { - size_t len = 0; + size_t len = content_len; // 注意:由于header_to_der没有输出数据,因此需要加上数据的长度,header length 才是正确的值 /* if (content_type == OID_cms_data) { return cms_content_info_data_header_to_der(content_len, out, outlen); } */ + if (cms_content_type_to_der(content_type, NULL, &len) != 1 || asn1_explicit_header_to_der(0, content_len, NULL, &len) < 0 || asn1_sequence_header_to_der(len, out, outlen) != 1 @@ -254,23 +250,43 @@ int cms_content_info_print(FILE *fp, int fmt, int ind, const char *label, const if (cms_content_type_from_der(&content_type, &d, &dlen) != 1) goto err; format_print(fp, fmt, ind, "contentType: %s\n", cms_content_type_name(content_type)); - if ((ret = asn1_explicit_from_der(0, &content, &content_len, &d, &dlen)) < 0) goto err; - if (ret) { + /* if (content_type == OID_cms_data) { if (asn1_octet_string_from_der(&p, &len, &content, &content_len) != 1) goto err; } else { if (asn1_sequence_from_der(&p, &len, &content, &content_len) != 1) goto err; } - switch (content_type) { - case OID_cms_data: format_bytes(fp, fmt, ind, "content", p, len); break; - case OID_cms_signed_data: cms_signed_data_print(fp, fmt, ind, "content", p, len); break; - case OID_cms_enveloped_data: cms_enveloped_data_print(fp, fmt, ind, "content", p, len); break; - case OID_cms_signed_and_enveloped_data: cms_signed_and_enveloped_data_print(fp, fmt, ind, "content", p, len); break; - case OID_cms_encrypted_data: cms_encrypted_data_print(fp, fmt, ind, "content", p, len); break; - case OID_cms_key_agreement_info: cms_key_agreement_info_print(fp, fmt, ind, "content", p, len); break; + */ + + //format_bytes(stderr, 0, 0, "content", d, dlen); + + if ((ret = asn1_explicit_from_der(0, &content, &content_len, &d, &dlen)) < 0) { error_print(); goto err; } + if (ret == 0) { error_print(); goto err; } + + if (content_type == OID_cms_data) { + if (asn1_octet_string_from_der(&p, &len, &content, &content_len) != 1 + || asn1_length_is_zero(content_len) != 1) { + error_print(); + return -1; } - if (asn1_length_is_zero(content_len) != 1) goto err; + format_bytes(fp, fmt, ind, "content", p, len); + return 1; } + + + if (asn1_sequence_from_der(&p, &len, &content, &content_len) != 1) { error_print(); goto err; } + + switch (content_type) { + //case OID_cms_data: format_bytes(fp, fmt, ind, "content", p, len); break; + case OID_cms_signed_data: cms_signed_data_print(fp, fmt, ind, "content", p, len); break; + case OID_cms_enveloped_data: cms_enveloped_data_print(fp, fmt, ind, "content", p, len); break; + case OID_cms_signed_and_enveloped_data: cms_signed_and_enveloped_data_print(fp, fmt, ind, "content", p, len); break; + case OID_cms_encrypted_data: cms_encrypted_data_print(fp, fmt, ind, "content", p, len); break; + case OID_cms_key_agreement_info: cms_key_agreement_info_print(fp, fmt, ind, "content", p, len); break; + } + if (asn1_length_is_zero(content_len) != 1) goto err; + + if (asn1_length_is_zero(dlen) != 1) goto err; return 1; err: @@ -367,8 +383,8 @@ int cms_enced_content_info_encrypt_to_der( { int ret; SM4_KEY sm4_key; - uint8_t enced_content[32 + content_len]; - size_t enced_content_len; + uint8_t enced_content[32 + content_len]; // FIXME: 如果content_len 过长,会直接导致segment fault + size_t enced_content_len = 100; if (enc_algor != OID_sm4_cbc || keylen != 16 || ivlen != 16) { error_print(); @@ -759,6 +775,7 @@ int cms_signer_info_sign_to_der( uint8_t **out, size_t *outlen) { SM3_CTX ctx = *sm3_ctx; + int fixed_outlen = 1; uint8_t dgst[SM3_DIGEST_SIZE]; uint8_t sig[SM2_MAX_SIGNATURE_SIZE]; size_t siglen; @@ -766,11 +783,12 @@ int cms_signer_info_sign_to_der( sm3_update(&ctx, authed_attrs, authed_attrs_len); sm3_finish(&ctx, dgst); - if (sm2_sign(sign_key, dgst, sig, &siglen) != 1) { + + + if (sm2_sign_ex(sign_key, fixed_outlen, dgst, sig, &siglen) != 1) { error_print(); return -1; } - if (cms_signer_info_to_der(CMS_version_v1, issuer, issuer_len, serial_number, serial_number_len, OID_sm3, authed_attrs, authed_attrs_len, @@ -1206,6 +1224,7 @@ int cms_signed_data_verify_from_der( &authed_attrs, &authed_attrs_len, &unauthed_attrs, &unauthed_attrs_len, &signer_infos, &signer_infos_len) != 1) { + error_print(); return -1; } @@ -1264,7 +1283,8 @@ int cms_recipient_info_from_der( serial_number, serial_number_len, &d, &dlen) != 1 || x509_public_key_encryption_algor_from_der(pke_algor, params, params_len, &d, &dlen) != 1 || asn1_octet_string_from_der(enced_key, enced_key_len, &d, &dlen) != 1 - || asn1_length_is_zero(dlen) != 1) { + // || asn1_length_is_zero(dlen) != 1 + ) { error_print(); return -1; } @@ -1317,12 +1337,14 @@ int cms_recipient_info_encrypt_to_der( int pke_algor = OID_sm2encrypt; uint8_t enced_key[SM2_MAX_CIPHERTEXT_SIZE]; size_t enced_key_len; + int fixed_outlen = 1; if (pke_algor != OID_sm2encrypt) { error_print(); return -1; } - if (sm2_encrypt(public_key, in, inlen, enced_key, &enced_key_len) != 1) { + + if (sm2_encrypt_ex(public_key, fixed_outlen, in, inlen, enced_key, &enced_key_len) != 1) { error_print(); return -1; } @@ -1554,7 +1576,6 @@ int cms_enveloped_data_encrypt_to_der( return -1; } } - len = 0; if (asn1_int_to_der(CMS_version_v1, NULL, &len) != 1 || asn1_set_to_der(rcpt_infos, rcpt_infos_len, NULL, &len) != 1 @@ -2048,9 +2069,20 @@ int cms_set_data(uint8_t *cms, size_t *cmslen, const uint8_t *d, size_t dlen) int oid = OID_cms_data; size_t len = 0; + if (asn1_octet_string_to_der(d, dlen, NULL, &len) < 0) { + error_print(); + return -1; + } *cmslen = 0; - if (asn1_octet_string_to_der(d, dlen, NULL, &len) < 0 - || cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 + if (!cms) { + uint8_t data[1]; + if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) { + error_print(); + return -1; + } + return 1; + } + if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 || asn1_octet_string_to_der(d, dlen, &cms, cmslen) < 0) { error_print(); return -1; @@ -2067,14 +2099,25 @@ int cms_encrypt(uint8_t *cms, size_t *cmslen, int oid = OID_cms_encrypted_data; size_t len = 0; - *cmslen = 0; if (cms_encrypted_data_encrypt_to_der( - enc_algor, key, keylen, iv, ivlen, - content_type, content, content_len, - shared_info1, shared_info1_len, - shared_info2, shared_info2_len, - NULL, &len) != 1 - || cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 + enc_algor, key, keylen, iv, ivlen, + content_type, content, content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + NULL, &len) != 1) { + error_print(); + return -1; + } + *cmslen = 0; + if (!cms) { + uint8_t data[1]; + if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) { + error_print(); + return -1; + } + return 1; + } + if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 || cms_encrypted_data_encrypt_to_der( enc_algor, key, keylen, iv, ivlen, content_type, content, content_len, @@ -2125,13 +2168,24 @@ int cms_sign(uint8_t *cms, size_t *cmslen, int oid = OID_cms_signed_data; size_t len = 0; - *cmslen = 0; if (cms_signed_data_sign_to_der( - signers, signers_cnt, - content_type, content, content_len, - crls, crls_len, - NULL, &len) != 1 - || cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 + signers, signers_cnt, + content_type, content, content_len, + crls, crls_len, + NULL, &len) != 1) { + error_print(); + return -1; + } + *cmslen = 0; + if (!cms) { + uint8_t data[1]; + if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) { + error_print(); + return -1; + } + return 1; + } + if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 || cms_signed_data_sign_to_der( signers, signers_cnt, content_type, content, content_len, @@ -2156,12 +2210,19 @@ int cms_verify(const uint8_t *cms, size_t cmslen, size_t cms_content_len; if (cms_content_info_from_der(&cms_type, &cms_content, &cms_content_len, &cms, &cmslen) != 1 - || asn1_check(cms_type != OID_cms_signed_data) != 1 - || asn1_check(cms_content && cms_content_len) != 1 || asn1_length_is_zero(cmslen) != 1) { error_print(); return -1; } + if (cms_type != OID_cms_signed_data) { + error_print(); + return -1; + } + if (cms_content_len <= 0) { + error_print(); + return -1; + } + if (cms_signed_data_verify_from_der( extra_certs, extra_certs_len, extra_crls, extra_crls_len, @@ -2188,15 +2249,26 @@ int cms_envelop( int oid = OID_cms_enveloped_data; size_t len = 0; - *cmslen = 0; if (cms_enveloped_data_encrypt_to_der( - rcpt_certs, rcpt_certs_len, - enc_algor, key, keylen, iv, ivlen, - content_type, content, content_len, - shared_info1, shared_info1_len, - shared_info2, shared_info2_len, - NULL, &len) != 1 - || cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 + rcpt_certs, rcpt_certs_len, + enc_algor, key, keylen, iv, ivlen, + content_type, content, content_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + NULL, &len) != 1) { + error_print(); + return -1; + } + *cmslen = 0; + if (!cms) { + uint8_t data[1]; + if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) { + error_print(); + return -1; + } + return 1; + } + if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 || cms_enveloped_data_encrypt_to_der( rcpt_certs, rcpt_certs_len, enc_algor, key, keylen, iv, ivlen, @@ -2272,17 +2344,28 @@ int cms_sign_and_envelop(uint8_t *cms, size_t *cmslen, int oid = OID_cms_signed_and_enveloped_data; size_t len = 0; - *cmslen = 0; if (cms_signed_and_enveloped_data_encipher_to_der( - signers, signers_cnt, - rcpt_certs, rcpt_certs_len, - enc_algor, key, keylen, iv, ivlen, - content_type, content, content_len, - crls, crls_len, - shared_info1, shared_info1_len, - shared_info2, shared_info2_len, - NULL, &len) != 1 - || cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 + signers, signers_cnt, + rcpt_certs, rcpt_certs_len, + enc_algor, key, keylen, iv, ivlen, + content_type, content, content_len, + crls, crls_len, + shared_info1, shared_info1_len, + shared_info2, shared_info2_len, + NULL, &len) != 1) { + error_print(); + return -1; + } + *cmslen = 0; + if (!cms) { + uint8_t data[1]; + if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) { + error_print(); + return -1; + } + return 1; + } + if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 || cms_signed_and_enveloped_data_encipher_to_der( signers, signers_cnt, rcpt_certs, rcpt_certs_len, @@ -2372,10 +2455,21 @@ int cms_set_key_agreement_info( int oid = OID_cms_key_agreement_info; size_t len = 0; - *cmslen = 0; if (cms_key_agreement_info_to_der(CMS_version_v1, temp_public_key_r, - user_cert, user_cert_len, user_id, user_id_len, NULL, &len) != 1 - || cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 + user_cert, user_cert_len, user_id, user_id_len, NULL, &len) != 1) { + error_print(); + return -1; + } + *cmslen = 0; + if (!cms) { + uint8_t data[1]; + if (cms_content_info_to_der(oid, data, len, NULL, cmslen) != 1) { + error_print(); + return -1; + } + return 1; + } + if (cms_content_info_header_to_der(oid, len, &cms, cmslen) != 1 || cms_key_agreement_info_to_der(CMS_version_v1, temp_public_key_r, user_cert, user_cert_len, user_id, user_id_len, &cms, cmslen) != 1) { error_print(); @@ -2384,16 +2478,41 @@ int cms_set_key_agreement_info( return 1; } +int cms_to_pem(const uint8_t *cms, size_t cms_len, FILE *fp) +{ + if (pem_write(fp, PEM_CMS, cms, cms_len) != 1) { + error_print(); + return -1; + } + return 1; +} + +int cms_from_pem(uint8_t *cms, size_t *cms_len, size_t maxlen, FILE *fp) +{ + int ret; + if ((ret = pem_read(fp, PEM_CMS, cms, cms_len, maxlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + + return 1; +} + int cms_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen) { const uint8_t *d; size_t dlen; + if (asn1_sequence_from_der(&d, &dlen, &a, &alen) != 1) goto err; + + cms_content_info_print(fp, fmt, ind, label, d, dlen); - if (asn1_length_is_zero(alen) != 1) goto err; + //if (asn1_length_is_zero(alen) != 1) goto err; return 1; err: error_print(); return -1; } + + diff --git a/src/digest.c b/src/digest.c index 8eac5582..a2bee668 100644 --- a/src/digest.c +++ b/src/digest.c @@ -62,7 +62,7 @@ typedef struct { DIGEST_TABLE digest_table[] = { { OID_sm3, "sm3", "SM3" }, - { OID_md5, "md5", "MD5" }, +// { OID_md5, "md5", "MD5" }, { OID_sha1, "sha1", "SHA-1" }, { OID_sha224, "sha224", "SHA-224" }, { OID_sha256, "sha256", "SHA-256" }, @@ -131,8 +131,10 @@ const DIGEST *digest_from_name(const char *name) { if (!strcmp(name, "sm3") || !strcmp(name, "SM3")) { return DIGEST_sm3(); + /* } else if (!strcmp(name, "md5") || !strcmp(name, "MD5")) { return DIGEST_md5(); + */ } else if (!strcmp(name, "sha1") || !strcmp(name, "SHA1")) { return DIGEST_sha1(); } else if (!strcmp(name, "sha224") || !strcmp(name, "SHA224")) { @@ -196,7 +198,7 @@ const DIGEST *DIGEST_sm3(void) return &sm3_digest_object; } - +/* #include static int md5_digest_init(DIGEST_CTX *ctx) @@ -243,6 +245,7 @@ const DIGEST *DIGEST_md5(void) { return &md5_digest_object; } +*/ #include @@ -292,7 +295,6 @@ const DIGEST *DIGEST_sha1(void) return &sha1_digest_object; } - #include static int sha224_digest_init(DIGEST_CTX *ctx) diff --git a/src/pem.c b/src/pem.c index f8f11235..82dd98c9 100644 --- a/src/pem.c +++ b/src/pem.c @@ -97,6 +97,10 @@ int pem_read(FILE *fp, const char *name, uint8_t *data, size_t *datalen, size_t if (strcmp(line, begin_line) != 0) { // FIXME: 这里是不是应该容忍一些错误呢? + + fprintf(stderr, "%s %d: %s\n", __FILE__, __LINE__, line); + fprintf(stderr, "%s %d: %s\n", __FILE__, __LINE__, begin_line); + error_print(); return -1; } diff --git a/src/sm2_alg.c b/src/sm2_alg.c index 702b3273..1dbd3ec7 100644 --- a/src/sm2_alg.c +++ b/src/sm2_alg.c @@ -697,12 +697,6 @@ void sm2_fn_mul(SM2_BN r, const SM2_BN a, const SM2_BN b) uint64_t c[9] = {0,0,0,0,0,0,0,0,0x100000000}; sm2_bn288_sub(q, c, q); sm2_bn288_add(zl, q, zl); - printf("******\n"); - printf("******\n"); - printf("******\n"); - printf("******\n"); - printf("******\n"); - } //printf("r = "); for (i = 8; i >= 0; i--) printf("%08x", (uint32_t)zl[i]); printf("\n"); diff --git a/src/sm2_lib.c b/src/sm2_lib.c index 5f58add4..2487b6d3 100644 --- a/src/sm2_lib.c +++ b/src/sm2_lib.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -58,7 +59,7 @@ #define print_bn(str,a) sm2_bn_print(stderr,0,4,str,a) -int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig) +int sm2_do_sign_ex(const SM2_KEY *key, int fixed_outlen, const uint8_t dgst[32], SM2_SIGNATURE *sig) { SM2_JACOBIAN_POINT _P, *P = &_P; SM2_BN d; @@ -68,12 +69,12 @@ int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig) SM2_BN r; SM2_BN s; +retry: sm2_bn_from_bytes(d, key->private_key); // e = H(M) sm2_bn_from_bytes(e, dgst); //print_bn("e", e); - -retry: + // e被重用了,注意retry的位置! // rand k in [1, n - 1] do { @@ -107,17 +108,31 @@ retry: sm2_fn_inv(e, e); //print_bn("(1+d)^-1", e); sm2_fn_mul(s, e, k); //print_bn("s = ((1 + d)^-1 * (k - r * d)) mod n", s); - sm2_bn_clean(d); - sm2_bn_clean(k); sm2_bn_to_bytes(r, sig->r); //print_bn("r", r); sm2_bn_to_bytes(s, sig->s); //print_bn("s", s); + if (fixed_outlen) { + uint8_t buf[72]; + uint8_t *p = buf; + size_t len = 0; + sm2_signature_to_der(sig, &p, &len); + if (len != 71) { + goto retry; + } + } - sm2_bn_clean(d); - sm2_bn_clean(k); + gmssl_secure_clear(d, sizeof(d)); + gmssl_secure_clear(e, sizeof(e)); + gmssl_secure_clear(k, sizeof(k)); + gmssl_secure_clear(x, sizeof(x)); return 1; } +int sm2_do_sign(const SM2_KEY *key, const uint8_t dgst[32], SM2_SIGNATURE *sig) +{ + return sm2_do_sign_ex(key, 0, dgst, sig); +} + int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATURE *sig) { SM2_JACOBIAN_POINT _P, *P = &_P; @@ -161,12 +176,12 @@ int sm2_do_verify(const SM2_KEY *key, const uint8_t dgst[32], const SM2_SIGNATUR sm2_bn_from_bytes(e, dgst); //print_bn("e = H(M)", e); sm2_fn_add(e, e, x); //print_bn("e + x (mod n)", e); + // check if r == r' - if (sm2_bn_cmp(e, r) == 0) { - return 1; - } else { + if (sm2_bn_cmp(e, r) != 0) { return 0; } + return 1; } int sm2_signature_to_der(const SM2_SIGNATURE *sig, uint8_t **out, size_t *outlen) @@ -231,7 +246,7 @@ int sm2_signature_print(FILE *fp, int fmt, int ind, const char *label, const uin #define SM2_SIGNATURE_MAX_DER_SIZE 77 -int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen) +int sm2_sign_ex(const SM2_KEY *key, int fixed_outlen, const uint8_t dgst[32], uint8_t *sig, size_t *siglen) { SM2_SIGNATURE signature; uint8_t *p; @@ -246,7 +261,7 @@ int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *s p = sig; *siglen = 0; - if (sm2_do_sign(key, dgst, &signature) != 1 + if (sm2_do_sign_ex(key, fixed_outlen, dgst, &signature) != 1 || sm2_signature_to_der(&signature, &p, siglen) != 1) { error_print(); return -1; @@ -254,6 +269,11 @@ int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *s return 1; } +int sm2_sign(const SM2_KEY *key, const uint8_t dgst[32], uint8_t *sig, size_t *siglen) +{ + return sm2_sign_ex(key, 0, dgst, sig, siglen); +} + int sm2_verify(const SM2_KEY *key, const uint8_t dgst[32], const uint8_t *sig, size_t siglen) { int ret; @@ -497,7 +517,7 @@ int sm2_kdf(const uint8_t *in, size_t inlen, size_t outlen, uint8_t *out) return 1; } -int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out) +int sm2_do_encrypt_ex(const SM2_KEY *key, int fixed_outlen, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out) { SM2_BN k; SM2_JACOBIAN_POINT _P, *P = &_P; @@ -505,15 +525,22 @@ int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPH uint8_t buf[64]; int i; +retry: // rand k in [1, n - 1] - do { - sm2_bn_rand_range(k, SM2_N); - } while (sm2_bn_is_zero(k)); + sm2_bn_rand_range(k, SM2_N); + if (sm2_bn_is_zero(k)) goto retry; // C1 = k * G = (x1, y1) sm2_jacobian_point_mul_generator(P, k); sm2_jacobian_point_to_bytes(P, (uint8_t *)&out->point); + if (fixed_outlen) { + size_t xlen = 0, ylen = 0; + asn1_integer_to_der(out->point.x, 32, NULL, &xlen); + if (xlen != 34) goto retry; + asn1_integer_to_der(out->point.y, 32, NULL, &ylen); + if (ylen != 34) goto retry; + } // Q = k * P = (x2, y2) sm2_jacobian_point_from_bytes(P, (uint8_t *)&key->public_key); @@ -543,6 +570,11 @@ int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPH return 1; } +int sm2_do_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, SM2_CIPHERTEXT *out) +{ + return sm2_do_encrypt_ex(key, 0, in, inlen, out); +} + int sm2_do_decrypt(const SM2_KEY *key, const SM2_CIPHERTEXT *in, uint8_t *out, size_t *outlen) { uint32_t inlen; @@ -683,7 +715,7 @@ int sm2_ciphertext_print(FILE *fp, int fmt, int ind, const char *label, const ui return 1; } -int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +int sm2_encrypt_ex(const SM2_KEY *key, int fixed_outlen, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) { SM2_CIPHERTEXT C; @@ -695,7 +727,7 @@ int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *ou error_print(); return -1; } - if (sm2_do_encrypt(key, in, inlen, &C) != 1) { + if (sm2_do_encrypt_ex(key, fixed_outlen, in, inlen, &C) != 1) { error_print(); return -1; } @@ -707,6 +739,11 @@ int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *ou return 1; } +int sm2_encrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) +{ + return sm2_encrypt_ex(key, 0, in, inlen, out, outlen); +} + int sm2_decrypt(const SM2_KEY *key, const uint8_t *in, size_t inlen, uint8_t *out, size_t *outlen) { SM2_CIPHERTEXT C; diff --git a/src/x509_alg.c b/src/x509_alg.c index 88ea49f7..4f36b414 100644 --- a/src/x509_alg.c +++ b/src/x509_alg.c @@ -53,8 +53,7 @@ #include #include #include - - +#include static uint32_t oid_sm3[] = { 1,2,156,10197,1,401 }; @@ -271,21 +270,20 @@ static uint32_t oid_rsasign_with_sha256[] = { 1,2,840,113549,1,1,11 }; static uint32_t oid_rsasign_with_sha384[] = { 1,2,840,113549,1,1,12 }; static uint32_t oid_rsasign_with_sha512[] = { 1,2,840,113549,1,1,13 }; -#define X509_ALGOR_OPT_NULL_PARAM 1 static const ASN1_OID_INFO x509_sign_algors[] = { - { OID_sm2sign_with_sm3, "sm2sign-with-sm3", oid_sm2sign_with_sm3, sizeof(oid_sm2sign_with_sm3)/sizeof(int), 0 }, - { OID_rsasign_with_sm3, "rsasign-with-sm3", oid_rsasign_with_sm3, sizeof(oid_rsasign_with_sm3)/sizeof(int), X509_ALGOR_OPT_NULL_PARAM }, - { OID_ecdsa_with_sha1, "ecdsa-with-sha1", oid_ecdsa_with_sha1, sizeof(oid_ecdsa_with_sha1)/sizeof(int), 0 }, - { OID_ecdsa_with_sha224, "ecdsa-with-sha224", oid_ecdsa_with_sha224, sizeof(oid_ecdsa_with_sha224)/sizeof(int), 0} , - { OID_ecdsa_with_sha256, "ecdsa-with-sha256", oid_ecdsa_with_sha256, sizeof(oid_ecdsa_with_sha256)/sizeof(int), 0}, - { OID_ecdsa_with_sha384, "ecdsa-with-sha384", oid_ecdsa_with_sha384, sizeof(oid_ecdsa_with_sha384)/sizeof(int), 0 }, - { OID_ecdsa_with_sha512, "ecdsa-with-sha512", oid_ecdsa_with_sha512, sizeof(oid_ecdsa_with_sha512)/sizeof(int), 0 }, - { OID_rsasign_with_sha1, "sha1WithRSAEncryption", oid_rsasign_with_sha1, sizeof(oid_rsasign_with_sha1)/sizeof(int), 0 }, - { OID_rsasign_with_sha224, "sha224WithRSAEncryption", oid_rsasign_with_sha224, sizeof(oid_rsasign_with_sha224)/sizeof(int), X509_ALGOR_OPT_NULL_PARAM }, - { OID_rsasign_with_sha256, "sha256WithRSAEncryption", oid_rsasign_with_sha256, sizeof(oid_rsasign_with_sha256)/sizeof(int), X509_ALGOR_OPT_NULL_PARAM }, - { OID_rsasign_with_sha384, "sha384WithRSAEncryption", oid_rsasign_with_sha384, sizeof(oid_rsasign_with_sha384)/sizeof(int), X509_ALGOR_OPT_NULL_PARAM }, - { OID_rsasign_with_sha512, "sha512WithRSAEncryption", oid_rsasign_with_sha512, sizeof(oid_rsasign_with_sha512)/sizeof(int), X509_ALGOR_OPT_NULL_PARAM }, + { OID_sm2sign_with_sm3, "sm2sign-with-sm3", oid_sm2sign_with_sm3, sizeof(oid_sm2sign_with_sm3)/sizeof(int), X509_ALGOR_ALLOW_EC_NULL_PARAM }, + { OID_rsasign_with_sm3, "rsasign-with-sm3", oid_rsasign_with_sm3, sizeof(oid_rsasign_with_sm3)/sizeof(int), 1 }, + { OID_ecdsa_with_sha1, "ecdsa-with-sha1", oid_ecdsa_with_sha1, sizeof(oid_ecdsa_with_sha1)/sizeof(int), X509_ALGOR_ALLOW_EC_NULL_PARAM }, + { OID_ecdsa_with_sha224, "ecdsa-with-sha224", oid_ecdsa_with_sha224, sizeof(oid_ecdsa_with_sha224)/sizeof(int), X509_ALGOR_ALLOW_EC_NULL_PARAM } , + { OID_ecdsa_with_sha256, "ecdsa-with-sha256", oid_ecdsa_with_sha256, sizeof(oid_ecdsa_with_sha256)/sizeof(int), X509_ALGOR_ALLOW_EC_NULL_PARAM }, + { OID_ecdsa_with_sha384, "ecdsa-with-sha384", oid_ecdsa_with_sha384, sizeof(oid_ecdsa_with_sha384)/sizeof(int), X509_ALGOR_ALLOW_EC_NULL_PARAM }, + { OID_ecdsa_with_sha512, "ecdsa-with-sha512", oid_ecdsa_with_sha512, sizeof(oid_ecdsa_with_sha512)/sizeof(int), X509_ALGOR_ALLOW_EC_NULL_PARAM }, + { OID_rsasign_with_sha1, "sha1WithRSAEncryption", oid_rsasign_with_sha1, sizeof(oid_rsasign_with_sha1)/sizeof(int), X509_ALGOR_ALLOW_EC_NULL_PARAM }, + { OID_rsasign_with_sha224, "sha224WithRSAEncryption", oid_rsasign_with_sha224, sizeof(oid_rsasign_with_sha224)/sizeof(int), 1 }, + { OID_rsasign_with_sha256, "sha256WithRSAEncryption", oid_rsasign_with_sha256, sizeof(oid_rsasign_with_sha256)/sizeof(int), 1 }, + { OID_rsasign_with_sha384, "sha384WithRSAEncryption", oid_rsasign_with_sha384, sizeof(oid_rsasign_with_sha384)/sizeof(int), 1 }, + { OID_rsasign_with_sha512, "sha512WithRSAEncryption", oid_rsasign_with_sha512, sizeof(oid_rsasign_with_sha512)/sizeof(int), 1 }, }; static const int x509_sign_algors_count = diff --git a/src/x509_cer.c b/src/x509_cer.c index fcfd3bc5..4e8b361f 100644 --- a/src/x509_cer.c +++ b/src/x509_cer.c @@ -329,16 +329,26 @@ int x509_attr_type_and_value_print(FILE *fp, int fmt, int ind, const char *label if (fmt & ASN1_FMT_FULL) { format_print(fp, fmt, ind, "%s\n", label); ind += 4; - } - if (x509_name_type_from_der(&oid, &d, &dlen) != 1) goto err; - if (fmt & ASN1_FMT_FULL) + + if (x509_name_type_from_der(&oid, &d, &dlen) != 1) goto err; asn1_object_identifier_print(fp, fmt, ind, "type", x509_name_type_name(oid), NULL, 0); - - if (x509_directory_name_from_der(&tag, &val, &vlen, &d, &dlen) != 1) goto err; - if (fmt & ASN1_FMT_FULL) - x509_directory_name_print(fp, fmt, ind, "value", tag, val, vlen); - else x509_directory_name_print(fp, fmt, ind, x509_name_type_name(oid), tag, val, vlen); - + if (oid == OID_email_address) { + if (asn1_ia5_string_from_der((const char **)&val, &vlen, &d, &dlen) != 1) goto err; + format_string(fp, fmt, ind, "value", val, vlen); + } else { + if (x509_directory_name_from_der(&tag, &val, &vlen, &d, &dlen) != 1) goto err; + x509_directory_name_print(fp, fmt, ind, "value", tag, val, vlen); + } + } else { + if (x509_name_type_from_der(&oid, &d, &dlen) != 1) { error_print(); goto err; } + if (oid == OID_email_address) { + if (asn1_ia5_string_from_der((const char **)&val, &vlen, &d, &dlen) != 1) goto err; + format_string(fp, fmt, ind, "emailAddress", val, vlen); + } else { + if (x509_directory_name_from_der(&tag, &val, &vlen, &d, &dlen) != 1) goto err; + x509_directory_name_print(fp, fmt, ind, x509_name_type_name(oid), tag, val, vlen); + } + } if (asn1_length_is_zero(dlen) != 1) goto err; return 1; err: @@ -398,12 +408,17 @@ int x509_rdn_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t format_print(fp, fmt, ind, "%s\n", label); ind += 4; } + if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) { + error_print(); + return -1; + } + x509_attr_type_and_value_print(fp, fmt, ind, "AttributeTypeAndValue", p, len); while (dlen) { if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) { error_print(); return -1; } - x509_attr_type_and_value_print(fp, fmt, ind, "AttributeTypeAndValue", p, len); + x509_attr_type_and_value_print(fp, fmt, ind + 4, "AttributeTypeAndValue", p, len); } return 1; } @@ -532,21 +547,43 @@ int x509_name_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t return 1; } -int x509_name_get_printable(const uint8_t *d, size_t dlen, char *str, size_t maxlen) -{ - error_print(); - return -1; -} - int x509_name_get_value_by_type(const uint8_t *d, size_t dlen, int oid, int *tag, const uint8_t **val, size_t *vlen) { - error_print(); - return -1; + const uint8_t *rdn_d; + size_t rdn_dlen; + + while (dlen) { + int attr_oid; + int attr_tag; + const uint8_t *attr_val; + size_t attr_vlen; + + if (asn1_set_from_der(&rdn_d, &rdn_dlen, &d, &dlen) != 1) { + error_print(); + return -1; + } + while (rdn_dlen) { + if (x509_attr_type_and_value_from_der(&attr_oid, &attr_tag, &attr_val, &attr_vlen, + &rdn_d, &rdn_dlen) != 1) { + error_print(); + return -1; + } + } + if (attr_oid == oid) { + *tag = attr_tag; + *val = attr_val; + *vlen = attr_vlen; + return 1; + } + } + return 0; } int x509_name_get_common_name(const uint8_t *d, size_t dlen, int *tag, const uint8_t **val, size_t *vlen) { - error_print(); + int ret; + ret = x509_name_get_value_by_type(d, dlen, OID_at_common_name, tag, val, vlen); + if (ret < 0) error_print(); return -1; } @@ -653,6 +690,7 @@ int x509_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t } break; case OID_ce_key_usage: + case OID_netscape_cert_type: if (asn1_bits_from_der(&ival, &val, &vlen) != 1) { error_print(); return -1; @@ -665,6 +703,11 @@ int x509_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t } break; case OID_netscape_cert_comment: + if (asn1_ia5_string_from_der((const char **)&p, &len, &val, &vlen) != 1) { + error_print(); + return -1; + } + break; case OID_ct_precertificate_scts: case OID_undef: p = val; @@ -700,6 +743,7 @@ int x509_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t case OID_ce_crl_distribution_points: return x509_crl_distribution_points_print(fp, fmt, ind, name, p, len); case OID_ce_inhibit_any_policy: format_print(fp, fmt, ind, "%s: %d\n", name, ival); case OID_ce_freshest_crl: return x509_freshest_crl_print(fp, fmt, ind, name, p, len); + case OID_netscape_cert_type: return x509_netscape_cert_type_print(fp, fmt, ind, name, ival); case OID_netscape_cert_comment: return format_string(fp, fmt, ind, name, p, len); default: format_bytes(fp, fmt, ind, "extnValue", p, len); } @@ -1132,12 +1176,15 @@ int x509_cert_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t format_print(fp, fmt, ind, "%s\n", label); ind += 4; - if (asn1_sequence_from_der(&d, &dlen, &a, &alen) != 1 - || asn1_length_is_zero(alen) != 1) { + if (asn1_sequence_from_der(&d, &dlen, &a, &alen) != 1) { error_print(); return -1; } x509_certificate_print(fp, fmt, ind, label, d, dlen); + if (asn1_length_is_zero(alen) != 1) { + error_print(); + return -1; + } return 1; } @@ -1307,10 +1354,27 @@ int x509_certs_to_pem(const uint8_t *d, size_t dlen, FILE *fp) return 1; } -int x509_certs_from_pem(const uint8_t *d, size_t *dlen, size_t maxlen, FILE *fp) +int x509_certs_from_pem(uint8_t *d, size_t *dlen, size_t maxlen, FILE *fp) { - error_print(); - return -1; + int ret; + size_t len, total_len = 0; + + for (;;) { + if ((ret = x509_cert_from_pem(d, &len, maxlen, fp)) < 0) { + error_print(); + return -1; + } else if (ret == 0) { + break; + } + d += len; + total_len += len; + maxlen -= len; + } + *dlen = total_len; + if (!total_len) { + return 0; + } + return 1; } int x509_certs_get_count(const uint8_t *d, size_t dlen, size_t *cnt) @@ -1324,15 +1388,42 @@ int x509_certs_get_count(const uint8_t *d, size_t dlen, size_t *cnt) int x509_certs_get_cert_by_index(const uint8_t *d, size_t dlen, int index, const uint8_t **cert, size_t *certlen) { - error_print(); - return -1; + const uint8_t *a; + size_t alen; + int ret, i; + + for (i = 0; i <= index; i++) { + if ((ret = x509_cert_from_der(&a, &alen, &d, &dlen)) != 1) { + if (ret < 0) error_print(); + else error_print(); + return -1; + } + } + *cert = a; + *certlen = alen; + return 1; } int x509_certs_get_cert_by_subject(const uint8_t *d, size_t dlen, const uint8_t *subject, size_t subject_len, const uint8_t **cert, size_t *certlen) { - error_print(); - return -1; + const uint8_t *a; + size_t alen; + const uint8_t *subj; + size_t subj_len; + + while (dlen) { + if (x509_cert_from_der(&a, &alen, &d, &dlen) != 1) { + error_print(); + return -1; + } + if (subj_len == subject_len && memcmp(subj, subject, subj_len) == 0) { + *cert = a; + *certlen = alen; + return 1; + } + } + return 0; } int x509_certs_get_cert_by_issuer_and_serial_number( diff --git a/src/x509_crl.c b/src/x509_crl.c index 2edbf45f..f5c7e6be 100644 --- a/src/x509_crl.c +++ b/src/x509_crl.c @@ -416,7 +416,6 @@ const char *x509_crl_ext_id_name(int oid) { const ASN1_OID_INFO *info; if (!(info = asn1_oid_info_from_oid(x509_crl_exts, x509_crl_exts_count, oid))) { - error_print(); return NULL; } return info->name; @@ -449,7 +448,7 @@ int x509_crl_ext_id_to_der(int oid, uint8_t **out, size_t *outlen) return 1; } -int x509_crl_ext_id_from_der(int *oid, const uint8_t **in, size_t *inlen) +int x509_crl_ext_id_from_der_ex(int *oid, uint32_t *nodes, size_t *nodes_cnt, const uint8_t **in, size_t *inlen) { int ret; const uint8_t *p; @@ -457,11 +456,13 @@ int x509_crl_ext_id_from_der(int *oid, const uint8_t **in, size_t *inlen) const ASN1_OID_INFO *info; *oid = 0; - if ((ret = asn1_oid_info_from_der(&info, x509_crl_exts, x509_crl_exts_count, in, inlen)) != 1) { + if ((ret = asn1_oid_info_from_der_ex(&info, nodes, nodes_cnt, x509_crl_exts, x509_crl_exts_count, in, inlen)) != 1) { error_print(); return -1; } - *oid = info->oid; + if (info) { + *oid = info->oid; + } return ret; } @@ -635,13 +636,15 @@ int x509_crl_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint size_t vlen; const uint8_t *p; size_t len; + uint32_t nodes[32]; + size_t nodes_cnt; int num; format_print(fp, fmt, ind, "%s\n", label); ind += 4; - if (x509_crl_ext_id_from_der(&oid, &d, &dlen) != 1) goto err; - format_print(fp, fmt, ind, "extnID: %s\n", x509_crl_ext_id_name(oid)); + if (x509_crl_ext_id_from_der_ex(&oid, nodes, &nodes_cnt, &d, &dlen) != 1) goto err; + asn1_object_identifier_print(fp, fmt, ind, "extnID", x509_crl_ext_id_name(oid), nodes, nodes_cnt); if ((ret = asn1_boolean_from_der(&critical, &d, &dlen)) < 0) goto err; if (ret) format_print(fp, fmt, ind, "critical: %s\n", asn1_boolean_name(critical)); if (asn1_octet_string_from_der(&v, &vlen, &d, &dlen) != 1) goto err; @@ -664,6 +667,11 @@ int x509_crl_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint return -1; } break; + default: + if (asn1_any_from_der(&p, &len, &v, &vlen) != 1) { + error_print(); + return -1; + } } name = x509_crl_ext_id_name(oid); @@ -676,6 +684,7 @@ int x509_crl_ext_print(FILE *fp, int fmt, int ind, const char *label, const uint case OID_ce_issuing_distribution_point: x509_issuing_distribution_point_print(fp, fmt, ind, name, p, len); break; case OID_ce_freshest_crl: x509_crl_distribution_points_print(fp, fmt, ind, name, p, len); break; case OID_pe_authority_info_access: x509_access_descriptions_print(fp, fmt, ind, name, p, len); break; + default: format_bytes(fp, fmt, ind, "value", p, len); } if (asn1_length_is_zero(vlen) != 1) goto err; return 1; @@ -873,12 +882,22 @@ err: // FIXME: 这两个函数应该检查CRL格式是否正确 int x509_crl_to_der(const uint8_t *a, size_t alen, uint8_t **out, size_t *outlen) { - return asn1_any_to_der(a, alen, out, outlen); + int ret; + if ((ret = asn1_any_to_der(a, alen, out, outlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + return 1; } int x509_crl_from_der(const uint8_t **a, size_t *alen, const uint8_t **in, size_t *inlen) { - return asn1_any_from_der(a, alen, in, inlen); + int ret; + if ((ret = asn1_any_from_der(a, alen, in, inlen)) != 1) { + if (ret < 0) error_print(); + return ret; + } + return 1; } int x509_crl_to_pem(const uint8_t *a, size_t alen, FILE *fp) @@ -900,6 +919,44 @@ int x509_crl_from_pem(uint8_t *a, size_t *alen, size_t maxlen, FILE *fp) return 1; } +int x509_crl_to_fp(const uint8_t *a, size_t alen, FILE *fp) +{ + if (fwrite(a, 1, alen, fp) != alen) { + error_print(); + return -1; + } + return 1; +} + +int x509_crl_from_fp(uint8_t *a, size_t *alen, size_t maxlen, FILE *fp) +{ + size_t len; + const uint8_t *d = a; + size_t dlen; + const uint8_t *crl; + size_t crl_len; + + if (!(len = fread(a, 1, maxlen, fp))) { + if (feof(fp)) { + return 0; + } else { + error_print(); + return -1; + } + } + + dlen = len; + if (x509_crl_from_der(&crl, &crl_len, &d, &dlen) != 1 + || asn1_length_is_zero(dlen) != 1) { + error_print(); + return -1; + } + + *alen = len; + return 1; +} + + int x509_crl_print(FILE *fp, int fmt, int ind, const char *label, const uint8_t *a, size_t alen) { const uint8_t *d; diff --git a/src/x509_ext.c b/src/x509_ext.c index d8c5824b..d0645fe0 100644 --- a/src/x509_ext.c +++ b/src/x509_ext.c @@ -463,16 +463,17 @@ int x509_general_name_from_der(int *choice, const uint8_t **d, size_t *dlen, con return ret; } switch (tag) { - case ASN1_TAG_IMPLICIT(0): *choice = 0; break; + case ASN1_TAG_EXPLICIT(0): *choice = 0; break; case ASN1_TAG_IMPLICIT(1): *choice = 1; break; case ASN1_TAG_IMPLICIT(2): *choice = 2; break; - case ASN1_TAG_IMPLICIT(3): *choice = 3; break; - case ASN1_TAG_IMPLICIT(4): *choice = 4; break; - case ASN1_TAG_IMPLICIT(5): *choice = 5; break; + case ASN1_TAG_EXPLICIT(3): *choice = 3; break; + case ASN1_TAG_EXPLICIT(4): *choice = 4; break; + case ASN1_TAG_EXPLICIT(5): *choice = 5; break; case ASN1_TAG_IMPLICIT(6): *choice = 6; break; case ASN1_TAG_IMPLICIT(7): *choice = 7; break; case ASN1_TAG_IMPLICIT(8): *choice = 8; break; default: + fprintf(stderr, "%s %d: tag = %x\n", __FILE__, __LINE__, tag); error_print(); return -1; } @@ -481,9 +482,24 @@ int x509_general_name_from_der(int *choice, const uint8_t **d, size_t *dlen, con int x509_general_name_print(FILE *fp, int fmt, int ind, const char *label, int choice, const uint8_t *d, size_t dlen) { + const uint8_t *p; + size_t len; + format_print(fp, fmt, ind, "%s\n", label); ind += 4; + switch (choice) { + case 0: + case 3: + case 4: + case 5: + if (asn1_sequence_from_der(&p, &len, &d, &dlen) != 1) { + error_print(); + return -1; + } + d = p; + dlen = len; + } switch (choice) { case 0: return x509_other_name_print(fp, fmt, ind, "otherName", d, dlen); case 1: return asn1_string_print(fp, fmt, ind, "rfc822Name", ASN1_TAG_IA5String, d, dlen); @@ -1211,19 +1227,18 @@ int x509_basic_constraints_from_der(int *ca, int *path_len_cons, const uint8_t * if ((ret = asn1_sequence_from_der(&d, &dlen, in, inlen)) != 1) { if (ret < 0) error_print(); - else { - *ca = -1; - *path_len_cons = -1; - }; return ret; } if (asn1_boolean_from_der(ca, &d, &dlen) < 0 || asn1_int_from_der(path_len_cons, &d, &dlen) < 0 - || asn1_check(ca >= 0 || path_len_cons >= 0) != 1 || asn1_length_is_zero(dlen) != 1) { error_print(); return -1; } + if (*ca < 0 && *path_len_cons < 0) { + error_print(); + return -1; + } if (*ca < 0) *ca = 0; return 1; } @@ -1237,6 +1252,7 @@ int x509_basic_constraints_print(FILE *fp, int fmt, int ind, const char *label, if ((ret = asn1_boolean_from_der(&val, &d, &dlen)) < 0) goto err; if (ret) format_print(fp, fmt, ind, "cA: %s\n", asn1_boolean_name(val)); + else format_print(fp, fmt, ind, "cA: %s\n", asn1_boolean_name(0)); // 特殊对待,无论cA值是否编码均输出结果 if ((ret = asn1_int_from_der(&val, &d, &dlen)) < 0) goto err; if (ret) format_print(fp, fmt, ind, "pathLenConstraint: %d\n", val); if (asn1_length_is_zero(dlen) != 1) goto err; @@ -1748,3 +1764,21 @@ int x509_distribution_points_print(FILE *fp, int fmt, int ind, const char *label } return 1; } + +static const char *netscape_cert_types[] = { + "SSL Client certificate", + "SSL Server certificate", + "S/MIME certificate", + "Object-signing certificate", + "Reserved for future use", + "SSL CA certificate", + "S/MIME CA certificate", + "Object-signing CA certificate", +}; + +int x509_netscape_cert_type_print(FILE *fp, int fmt, int ind, const char *label, int bits) +{ + return asn1_bits_print(fp, fmt, ind, label, netscape_cert_types, + sizeof(netscape_cert_types)/sizeof(netscape_cert_types[0]), bits); +} + diff --git a/src/x509_oid.c b/src/x509_oid.c index e0f55570..5107f7a9 100644 --- a/src/x509_oid.c +++ b/src/x509_oid.c @@ -75,6 +75,7 @@ static uint32_t oid_at_country_name[] = { oid_at,6 }; static uint32_t oid_at_serial_number[] = { oid_at,5 }; static uint32_t oid_at_pseudonym[] = { oid_at,65 }; static uint32_t oid_domain_component[] = { 0,9,2342,19200300,100,1,25 }; +static uint32_t oid_email_address[] = { 1,2,840,113549,1,9,1 }; #define OID_AT_CNT (sizeof(oid_at_name)/sizeof(int)) @@ -95,6 +96,7 @@ static const ASN1_OID_INFO x509_name_types[] = { { OID_at_serial_number, "serialNumber", oid_at_serial_number, OID_AT_CNT }, { OID_at_pseudonym, "pseudonym", oid_at_pseudonym, OID_AT_CNT }, { OID_domain_component, "domainComponent", oid_domain_component, sizeof(oid_domain_component)/sizeof(int) }, + { OID_email_address, "emailAddress", oid_email_address, sizeof(oid_email_address)/sizeof(int) }, }; static const int x509_name_types_count @@ -168,6 +170,7 @@ static uint32_t oid_ce_crl_reasons[] = { oid_ce,21 }; // crl_entry_ext static uint32_t oid_ce_invalidity_date[] = { oid_ce,24 }; // crl_entry_ext static uint32_t oid_ce_certificate_issuer[] = { oid_ce,29 }; // crl_entry_ext #define OID_CE_CNT sizeof(oid_ce_subject_directory_attributes)/sizeof(int) +static uint32_t oid_netscape_cert_type[] = { 2,16,840,1,113730,1,1 }; static uint32_t oid_netscape_cert_comment[] = { 2,16,840,1,113730,1,13 }; static uint32_t oid_cert_authority_info_access[] = { 1,3,6,1,5,5,7,1,1 }; static uint32_t oid_ct_precertificate_scts[] = { 1,3,6,1,4,1,11129,2,4,2 }; @@ -191,6 +194,7 @@ static const ASN1_OID_INFO x509_ext_ids[] = { { OID_ce_crl_reasons, "CRLReasons", oid_ce_crl_reasons, OID_CE_CNT }, { OID_ce_invalidity_date, "InvalidityDate", oid_ce_invalidity_date, OID_CE_CNT }, { OID_ce_certificate_issuer, "CertificateIssuer", oid_ce_certificate_issuer, OID_CE_CNT }, + { OID_netscape_cert_type, "NetscapeCertType", oid_netscape_cert_type, sizeof(oid_netscape_cert_type)/sizeof(int) }, { OID_netscape_cert_comment, "NetscapeCertComment", oid_netscape_cert_comment, sizeof(oid_netscape_cert_comment)/sizeof(int) }, { OID_cert_authority_info_access, "CertificateAuthorityInformationAccess", oid_cert_authority_info_access, sizeof(oid_cert_authority_info_access)/sizeof(int) }, { OID_ct_precertificate_scts, "CT-PrecertificateSCTs", oid_ct_precertificate_scts, sizeof(oid_ct_precertificate_scts)/sizeof(int) }, diff --git a/tests/digesttest.c b/tests/digesttest.c index 4c5068b1..ac133b30 100644 --- a/tests/digesttest.c +++ b/tests/digesttest.c @@ -53,7 +53,7 @@ #include const char *digests[] = { - "md5", +// "md5", "sha1", "sm3", "sha224", diff --git a/tools/certgen.c b/tools/certgen.c index 5f1827e7..a3d7a477 100644 --- a/tools/certgen.c +++ b/tools/certgen.c @@ -47,14 +47,22 @@ */ #include +#include #include #include -#include +#include +#include +#include +#include #include #include -#include -#include -#include + + +static const char *options = + "[-C str] [-ST str] [-L str] [-O str] [-OU str] -CN str -days num " + "-key file [-pass pass] " + "[-key_usage str]* [-out file]"; + static int ext_key_usage_set(int *usages, const char *usage_name) { @@ -67,18 +75,6 @@ static int ext_key_usage_set(int *usages, const char *usage_name) return 1; } - -#ifndef WIN32 -#include -#include -#endif - -static const char *options = - "[-C str] [-ST str] [-L str] [-O str] [-OU str] -CN str -days num " - "-key file [-pass pass] " - "[-key_usage str]*"; - - int certgen_main(int argc, char **argv) { int ret = 1; @@ -91,12 +87,10 @@ int certgen_main(int argc, char **argv) char *common_name = NULL; int days = 0; int key_usage = 0; - char *file = NULL; - FILE *outfp = stdout; - FILE *keyfp = NULL; + char *keyfile = NULL; char *pass = NULL; + char *outfile = NULL; - SM2_KEY sm2_key; uint8_t serial[12]; uint8_t name[256]; size_t namelen; @@ -105,17 +99,25 @@ int certgen_main(int argc, char **argv) uint8_t uniq_id[32]; uint8_t exts[512]; size_t extslen = 0; + FILE *keyfp = NULL; + SM2_KEY sm2_key; uint8_t cert[1024]; size_t certlen; + FILE *outfp = stdout; argc--; argv++; + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + while (argc > 0) { if (!strcmp(*argv, "-help")) { -help: printf("usage: %s %s\n", prog, options); - return 0; + ret = 0; + goto end; } else if (!strcmp(*argv, "-CN")) { if (--argc < 1) goto bad; common_name = *(++argv); @@ -137,64 +139,66 @@ help: } else if (!strcmp(*argv, "-days")) { if (--argc < 1) goto bad; days = atoi(*(++argv)); + if (days <= 0) { + fprintf(stderr, "%s: invalid '-days' value\n", prog); + goto end; + } } else if (!strcmp(*argv, "-key_usage")) { if (--argc < 1) goto bad; if (ext_key_usage_set(&key_usage, *(++argv)) != 1) { - error_print(); - return -1; + fprintf(stderr, "%s: invalid -key_usage value\n", prog); + goto end; } } else if (!strcmp(*argv, "-key")) { if (--argc < 1) goto bad; - file = *(++argv); - if (!(keyfp = fopen(file, "r"))) { - error_print(); - return -1; + keyfile = *(++argv); + if (!(keyfp = fopen(keyfile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno)); + goto end; } } else if (!strcmp(*argv, "-pass")) { if (--argc < 1) goto bad; pass = *(++argv); } else if (!strcmp(*argv, "-out")) { if (--argc < 1) goto bad; - file = *(++argv); - if (!(outfp = fopen(file, "w"))) { - error_print(); - return -1; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; } } else { -bad: fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); - fprintf(stderr, "usage: %s %s\n", prog, options); - return 1; + goto end; +bad: + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; } argc--; argv++; } - if (!common_name || days <= 0) { - fprintf(stderr, "%s: missing options\n", prog); - fprintf(stderr, "usage: %s %s\n", prog, options); - return 1; + if (!common_name) { + fprintf(stderr, "%s: '-CN' option required\n", prog); + goto end; + } + if (!days) { + fprintf(stderr, "%s: '-days' option required\n", prog); + goto end; + } + if (!keyfile) { + fprintf(stderr, "%s: '-key' option required\n", prog); + goto end; } - if (!pass) { - pass = getpass("Encryption Password : "); - } - if (!pass || strlen(pass) == 0) { fprintf(stderr, "%s: '-pass' option required\n", prog); - error_print(); - return -1; - } - - if (keyfp == NULL) { - error_print(); - return -1; - } - if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) { - error_print(); goto end; } + if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) { + fprintf(stderr, "%s: load private key failed\n", prog); + goto end; + } time(¬_before); if (rand_bytes(serial, sizeof(serial)) != 1 || x509_name_set(name, &namelen, sizeof(name), @@ -213,14 +217,19 @@ bad: NULL, 0, NULL, 0, exts, extslen, - &sm2_key, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1 - || x509_cert_to_pem(cert, certlen, outfp) != 1) { - error_print(); - return -1; + &sm2_key, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } + if (x509_cert_to_pem(cert, certlen, outfp) != 1) { + fprintf(stderr, "%s: output certificate failed\n", prog); + goto end; } ret = 0; end: - memset(&sm2_key, 0, sizeof(SM2_KEY)); + gmssl_secure_clear(&sm2_key, sizeof(SM2_KEY)); + if (keyfp) fclose(keyfp); + if (outfile && outfp) fclose(outfp); return ret; } diff --git a/tools/certparse.c b/tools/certparse.c index d04a12ce..8143df86 100644 --- a/tools/certparse.c +++ b/tools/certparse.c @@ -47,20 +47,23 @@ */ #include +#include #include #include #include #include -#include -static const char *options = "[-in file]"; + +static const char *options = "[-in file] [-out file]"; int certparse_main(int argc, char **argv) { + int ret = 1; char *prog = argv[0]; char *infile = NULL; + char *outfile = NULL; FILE *infp = stdin; - + FILE *outfp = stdout; uint8_t cert[18192]; size_t certlen; @@ -70,38 +73,49 @@ int certparse_main(int argc, char **argv) while (argc > 0) { if (!strcmp(*argv, "-help")) { printf("usage: %s %s\n", prog, options); - return 0; + goto end; } else if (!strcmp(*argv, "-in")) { if (--argc < 1) goto bad; infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; bad: - fprintf(stderr, "%s: llegal option '%s'\n", prog, *argv); - printf("usage: %s %s\n", prog, options); - return 1; + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; } argc--; argv++; } - if (infile) { - if (!(infp = fopen(infile, "r"))) { - error_print(); - return -1; + for (;;) { + int rv; + if ((rv = x509_cert_from_pem(cert, &certlen, sizeof(cert), infp)) != 1) { + if (rv < 0) fprintf(stderr, "%s: read certificate failure\n", prog); + else ret = 0; + goto end; + } + x509_cert_print(outfp, 0, 0, "Certificate", cert, certlen); + if (x509_cert_to_pem(cert, certlen, outfp) != 1) { + fprintf(stderr, "%s: output certficate failure\n", prog); + goto end; } } - for (;;) { - int ret; - if ((ret = x509_cert_from_pem(cert, &certlen, sizeof(cert), infp)) < 0) { - error_print(); - return -1; - } else if (!ret) { - break; - } - x509_cert_print(stdout, 0, 0, "Certificate", cert, certlen); - x509_cert_to_pem(cert, certlen, stdout); - } - return 0; +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + return ret; } diff --git a/tools/certverify.c b/tools/certverify.c index d6e9f914..550bca64 100644 --- a/tools/certverify.c +++ b/tools/certverify.c @@ -47,94 +47,98 @@ */ #include +#include #include #include -#include #include -#include -#include -#include -// 验证证书链是一个重量级的功能,应准备相应的文档,列举所有验证项目 -// 比如最基本的是证书中的签名、有效期、各个扩展等 -// 外部相关的:证书链、CRL等 + +static const char *options = "[-in pem] -cacert pem (-id str)\n"; int certverify_main(int argc, char **argv) { - int ret = 0; + int ret = 1; char *prog = argv[0]; - char *certfile = NULL; - FILE *certfp = NULL; - + char *infile = NULL; char *cacertfile = NULL; + FILE *infp = stdin; FILE *cacertfp = NULL; - uint8_t cert[1024]; size_t certlen; + const uint8_t *issuer; + size_t issuer_len; uint8_t cacert[1024]; size_t cacertlen; char *signer_id = SM2_DEFAULT_ID; - - SM2_KEY ca_pubkey; + int rv; argc--; argv++; - while (argc >= 1) { - if (!strcmp(*argv, "-help")) { - printf("Usage: %s [-cert pem] -cacert pem\n", prog); - return 0; + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 0) { + if (!strcmp(*argv, "-help")) { + printf("usage: %s %s\n", prog, options); + ret = 0; + goto end; } else if (!strcmp(*argv, "-cert")) { if (--argc < 1) goto bad; - certfile = *(++argv); - if (!(certfp = fopen(certfile, "r"))) { - error_print(); - return -1; + infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; } } else if (!strcmp(*argv, "-cacert")) { if (--argc < 1) goto bad; cacertfile = *(++argv); if (!(cacertfp = fopen(cacertfile, "r"))) { - error_print(); - return -1; + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, cacertfile, strerror(errno)); + goto end; } + } else if (!strcmp(*argv, "-id")) { + if (--argc < 1) goto bad; + signer_id = *(++argv); } else { - printf("Usage: %s [-cert pem] -cacert pem\n", prog); - return 0; - break; + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; } argc--; argv++; } - if (!certfp || !cacertfp) { - error_print(); - return -1; + if (!cacertfile) { + fprintf(stderr, "%s: '-cacert' option required\n", prog); + goto end; } - - if (x509_cert_from_pem(cert, &certlen, sizeof(cert), certfp) != 1) { - error_print(); - return -1; + if (x509_cert_from_pem(cert, &certlen, sizeof(cert), infp) != 1) { + fprintf(stderr, "%s: read certificate failure\n", prog); + goto end; } - if (x509_cert_from_pem(cacert, &cacertlen, sizeof(cacert), cacertfp) != 1) { - error_print(); - return -1; + if (x509_cert_get_subject(cert, certlen, &issuer, &issuer_len) != 1) { + fprintf(stderr, "%s: parse certificate error\n", prog); + goto end; } - if (x509_cert_verify_by_ca_cert(cert, certlen, cacert, cacertlen, signer_id, strlen(signer_id)) != 1) { - error_print(); - return -1; + if (x509_cert_from_pem_by_subject(cacert, &cacertlen, sizeof(cacert), issuer, issuer_len, cacertfp) != 1) { + fprintf(stderr, "%s: load CA certificate failure\n", prog); + goto end; } - ret = 1; - printf("Verification %s\n", ret ? "success" : "failure"); - + if ((rv = x509_cert_verify_by_ca_cert(cert, certlen, cacert, cacertlen, signer_id, strlen(signer_id))) < 0) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } + printf("Verification %s\n", rv ? "success" : "failure"); ret = 0; - goto end; - -bad: - fprintf(stderr, "%s: commands should not be used together\n", prog); - end: + if (infile && infp) fclose(infp); + if (cacertfp) fclose(cacertfp); return ret; } diff --git a/tools/cmsdecrypt.c b/tools/cmsdecrypt.c new file mode 100644 index 00000000..93570f7b --- /dev/null +++ b/tools/cmsdecrypt.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + + + +static const char *options = "-key file -pass str -cert file -in file [-out file]"; + +int cmsdecrypt_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *keyfile = NULL; + char *pass = NULL; + char *certfile = NULL; + char *infile = NULL; + char *outfile = NULL; + FILE *keyfp = NULL; + FILE *certfp = NULL; + FILE *infp = NULL; + FILE *outfp = stdout; + uint8_t cert[1024]; + size_t certlen; + struct stat st; + uint8_t *cms = NULL; + size_t cmslen, cms_maxlen; + SM2_KEY key; + int content_type; + uint8_t *content = NULL; + size_t content_len; + const uint8_t *rcpt_infos; + size_t rcpt_infos_len; + const uint8_t *shared_info1; + const uint8_t *shared_info2; + size_t shared_info1_len, shared_info2_len; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + printf("usage: %s %s\n", prog, options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + if (!(keyfp = fopen(keyfile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-pass")) { + if (--argc < 1) goto bad; + pass = *(++argv); + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + if (!(certfp = fopen(certfile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, certfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!keyfile) { + fprintf(stderr, "%s: '-key' option required\n", prog); + goto end; + } + if (!pass) { + fprintf(stderr, "%s: '-pass' option required\n", prog); + goto end; + } + if (!certfile) { + fprintf(stderr, "%s: '-cert' option required\n", prog); + goto end; + } + if (!infile) { + fprintf(stderr, "%s: '-in' option required\n", prog); + goto end; + } + + if (sm2_private_key_info_decrypt_from_pem(&key, pass, keyfp) != 1) { + fprintf(stderr, "%s: private key decryption failure\n", prog); + goto end; + } + if (x509_cert_from_pem(cert, &certlen, sizeof(cert), certfp) != 1) { + fprintf(stderr, "%s: load certificate failure\n", prog); + goto end; + } + + fstat(fileno(infp), &st); + cms_maxlen = (st.st_size * 3)/4 + 1; + if (!(cms = malloc(cms_maxlen))) { + fprintf(stderr, "%s: malloc failure\n", prog); + goto end; + } + if (cms_from_pem(cms, &cmslen, cms_maxlen, infp) != 1) { + fprintf(stderr, "%s: read CMS failure\n", prog); + goto end; + } + + if (!(content = malloc(cmslen))) { + fprintf(stderr, "%s: malloc failure\n", prog); + goto end; + } + + if (cms_deenvelop(cms, cmslen, + &key, cert, certlen, + &content_type, content, &content_len, + &rcpt_infos, &rcpt_infos_len, + &shared_info1, &shared_info1_len, + &shared_info2, &shared_info2_len) != 1) { + fprintf(stderr, "%s: decryption failure\n", prog); + goto end; + } + if (content_type != OID_cms_data) { + fprintf(stderr, "%s: invalid CMS content type: %s\n", prog, cms_content_type_name(content_type)); + goto end; + } + + if (fwrite(content, 1, content_len, outfp) != content_len) { + fprintf(stderr, "%s: output failure : %s\n", prog, strerror(errno)); + goto end; + } + + ret = 0; + +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + if (keyfile && keyfp) fclose(keyfp); + if (cms) free(cms); + if (content) free(content); + return ret; +} diff --git a/tools/cmsencrypt.c b/tools/cmsencrypt.c new file mode 100644 index 00000000..437ad44b --- /dev/null +++ b/tools/cmsencrypt.c @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + +签名的时候要提供签名者的证书,并且提供签名私钥 +但是验证的时候假定CMS中已经包含签名者的证书了,但是我们要提供CA证书库 + +加密的时候要指定接收者的证书,并且可以有多个接收者 +解密的时候只提供一个解密私钥,但是最好配合解密者的证书,从这个证书中找到解密者的名字 + +如果即加密又签名,那么输出的是SignedAndEnveloped + +CMS有PEM吗? + +cms -encrypt -rcpt a.pem -rcpt b.pem -rcpt c.pem -in file -sign -signcert a.pem -signcert b.pem + -rcptcert -rcpt_cert -sign_cert b.pem -signkey + +首先接收者可以有多个证书 + +这里面有个问题,因为我们要输出一个加密的对象,因此我们必须把输入的内容读取进来。 + + +EnvelopedData 是一个封装的SEQUENCE中,因此必须读取所有的内容。 +如果是一个文件,就需要读取所有的文件内容,如果是一个stream ,也需要读取完整的内容到一个足够大的buffer中,如何设置这个buffer的大小呢 + + + +对于输入文件,如果输入有文件名的话,可以直接通过stat获取文件长度 +但是如果对于stream的话,实际上我们是没有办法获得输入长度的,那么就直接准备一个buffer好了。 +不要给自己找麻烦了,直接只支持文件输入吧 +encrypt + +*/ + +static const char *options = "-encrypt (-rcptcert pem)* -in file -out file"; + + +static int get_files_size(int argc, char **argv, const char *option, size_t *len) +{ + char *prog = argv[0]; + char *file = NULL; + FILE *fp = NULL; + struct stat st; + + argc--; + argv++; + + *len = 0; + while (argc > 1) { + if (!strcmp(*argv, option)) { + if (--argc < 1) { + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + return -1; + } + file = *(++argv); + if (!(fp = fopen(file, "r"))) { + fprintf(stderr, "%s: open '%s' failed : %s\n", prog, file, strerror(errno)); + return -1; + } + if (fstat(fileno(fp), &st) < 0) { + fprintf(stderr, "%s: access '%s' failed : %s\n", prog, file, strerror(errno)); + fclose(fp); + return -1; + } + *len += st.st_size; + fclose(fp); + } + argc--; + argv++; + } + + return 1; +} + +int cmsencrypt_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + int op = 0; + char *infile = NULL; + char *outfile = NULL; + FILE *infp = stdin; + FILE *outfp = stdout; + uint8_t *rcpt_certs = NULL; + size_t rcpt_certs_len; + uint8_t key[16]; + uint8_t iv[16]; + uint8_t *inbuf = NULL; + size_t inlen; + uint8_t *cms = NULL; + size_t cmslen; + uint8_t *cert; + + if (argc < 2) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + // 预先统计证书缓冲大小和输入大小 + if (get_files_size(argc, argv, "-rcptcert", &rcpt_certs_len) != 1) { + goto end; + } + if (rcpt_certs_len <= 0) { + fprintf(stderr, "%s: invalid cert length\n", prog); + goto end; + } + rcpt_certs_len = (rcpt_certs_len * 3)/4; + if (!(rcpt_certs = malloc(rcpt_certs_len))) { + fprintf(stderr, "%s: malloc failure\n", prog); + goto end; + } + cert = rcpt_certs; + + if (get_files_size(argc, argv, "-in", &inlen) != 1) { + goto end; + } + if (inlen <= 0) { + fprintf(stderr, "%s: invalid input length\n", prog); + goto end; + } + if (!(inbuf = malloc(inlen))) { + fprintf(stderr, "%s: %s\n", prog, strerror(errno)); + goto end; + } + + argc--; + argv++; + + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + printf("usage: %s %s\n", prog, options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-rcptcert")) { + char *certfile; + FILE *certfp; + size_t certlen; + if (--argc < 1) goto bad; + certfile = *(++argv); + if (!(certfp = fopen(certfile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, certfile, strerror(errno)); + goto end; + } + if (x509_cert_from_pem(cert, &certlen, rcpt_certs_len, certfp) != 1) { + fprintf(stderr, "%s: error\n", prog); + fclose(certfp); + goto end; + } + cert += certlen; + fclose(certfp); + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + if ((inlen = fread(inbuf, 1, inlen, infp)) <= 0) { + fprintf(stderr, "%s: read data error: %s\n", prog, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + rcpt_certs_len = cert - rcpt_certs; + + if (rand_bytes(key, sizeof(key)) != 1 + || rand_bytes(iv, sizeof(iv)) != 1 + || cms_envelop(NULL, &cmslen, rcpt_certs, rcpt_certs_len, + OID_sm4_cbc, key, sizeof(key), iv, sizeof(iv), + OID_cms_data, inbuf, inlen, NULL, 0, NULL, 0) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } + if (!(cms = malloc(cmslen))) { + fprintf(stderr, "%s: malloc failure\n", prog); + goto end; + } + if (cms_envelop(cms, &cmslen, rcpt_certs, rcpt_certs_len, + OID_sm4_cbc, key, sizeof(key), iv, sizeof(iv), + OID_cms_data, inbuf, inlen, NULL, 0, NULL, 0) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } + if (cms_to_pem(cms, cmslen, outfp) != 1) { + fprintf(stderr, "%s: output CMS failure\n", prog); + goto end; + } + + ret = 0; + +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + if (rcpt_certs) free(rcpt_certs); + if (cms) free(cms); + return ret; +} diff --git a/tools/cmsparse.c b/tools/cmsparse.c new file mode 100644 index 00000000..14106fad --- /dev/null +++ b/tools/cmsparse.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +static const char *options = "-in file"; + +int cmsparse_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *infile = NULL; + FILE *infp = stdin; + struct stat st; + uint8_t *cms = NULL; + size_t cms_maxlen, cmslen; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + printf("usage: %s %s\n", prog, options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!infile) { + fprintf(stderr, "%s: option '-in' required'\n", prog); + goto end; + } + + if (fstat(fileno(infp), &st) < 0) { + fprintf(stderr, "%s: access '%s' failed : %s\n", prog, infile, strerror(errno)); + goto end; + } + cms_maxlen = (st.st_size * 3)/4 + 1; + if (!(cms = malloc(cms_maxlen))) { + fprintf(stderr, "%s: malloc failure\n", prog); + goto end; + } + if (cms_from_pem(cms, &cmslen, cms_maxlen, infp) != 1) { + fprintf(stderr, "%s: parse CMS error\n", prog); + goto end; + } + cms_print(stdout, 0, 0, "CMS", cms, cmslen); + ret = 0; +end: + if (infp) fclose(infp); + if (cms) free(cms); + return ret; +} diff --git a/tools/cmssign.c b/tools/cmssign.c new file mode 100644 index 00000000..683a21b1 --- /dev/null +++ b/tools/cmssign.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* +302 typedef struct { +303 uint8_t *certs; +304 size_t certs_len; +305 SM2_KEY *sign_key; +306 } CMS_CERTS_AND_KEY; + + + +输出长度主要由输入长度和 + +*/ + +static const char *options = "-key file -pass str -cert file -in file [-out file]"; + +int cmssign_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *keyfile = NULL; + char *pass = NULL; + char *certfile = NULL; + char *infile = NULL; + char *outfile = NULL; + FILE *keyfp = NULL; + FILE *certfp = NULL; + FILE *infp = NULL; + FILE *outfp = stdout; + SM2_KEY key; + uint8_t cert[1024]; + size_t certlen; + struct stat st; + uint8_t *in = NULL; + size_t inlen; + uint8_t *cms = NULL; + size_t cmslen, cms_maxlen; + CMS_CERTS_AND_KEY cert_and_key; + + int content_type; + uint8_t *content = NULL; + size_t content_len; + + const uint8_t *rcpt_infos; + size_t rcpt_infos_len; + const uint8_t *shared_info1; + const uint8_t *shared_info2; + size_t shared_info1_len, shared_info2_len; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + printf("usage: %s %s\n", prog, options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-key")) { + if (--argc < 1) goto bad; + keyfile = *(++argv); + if (!(keyfp = fopen(keyfile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-pass")) { + if (--argc < 1) goto bad; + pass = *(++argv); + } else if (!strcmp(*argv, "-cert")) { + if (--argc < 1) goto bad; + certfile = *(++argv); + if (!(certfp = fopen(certfile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, certfile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!keyfile) { + fprintf(stderr, "%s: '-key' option required\n", prog); + goto end; + } + if (!pass) { + fprintf(stderr, "%s: '-pass' option required\n", prog); + goto end; + } + if (!certfile) { + fprintf(stderr, "%s: '-cert' option required\n", prog); + goto end; + } + if (!infile) { + fprintf(stderr, "%s: '-in' option required\n", prog); + goto end; + } + + if (sm2_private_key_info_decrypt_from_pem(&key, pass, keyfp) != 1) { + fprintf(stderr, "%s: private key decryption failure\n", prog); + goto end; + } + if (x509_cert_from_pem(cert, &certlen, sizeof(cert), certfp) != 1) { + fprintf(stderr, "%s: load certificate failure\n", prog); + goto end; + } + { + SM2_KEY public_key; + if (x509_cert_get_subject_public_key(cert, certlen, &public_key) != 1) { + fprintf(stderr, "%s: parse certficate failure\n", prog); + goto end; + } + if (sm2_public_key_equ(&key, &public_key) != 1) { + fprintf(stderr, "%s: key and cert are not match!\n", prog); + goto end; + } + } + + cert_and_key.certs = cert; + cert_and_key.certs_len = certlen; + cert_and_key.sign_key = &key; + + if (fstat(fileno(infp), &st) < 0) { + fprintf(stderr, "%s: access file error : %s\n", prog, strerror(errno)); + goto end; + } + if ((inlen = st.st_size) <= 0) { + fprintf(stderr, "%s: invalid input length\n", prog); + goto end; + } + if (!(in = malloc(inlen))) { + fprintf(stderr, "%s: malloc failure\n", prog); + goto end; + } + if (fread(in, 1, inlen, infp) != inlen) { + fprintf(stderr, "%s: read file error : %s\n", prog, strerror(errno)); + goto end; + } + + cms_maxlen = (inlen * 4)/3 + 4096; // 主要由SignerInfos,其中的DN长度决定 + if (!(cms = malloc(cms_maxlen))) { + fprintf(stderr, "%s: malloc failure\n", prog); + goto end; + } + + if (cms_sign(cms, &cmslen, &cert_and_key, 1, OID_cms_data, in, inlen, NULL, 0) != 1) { + fprintf(stderr, "%s: sign failure\n", prog); + goto end; + } + + if (cms_to_pem(cms, cmslen, outfp) != 1) { + fprintf(stderr, "%s: output failure\n", prog); + goto end; + } + + ret = 0; + +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + if (keyfile && keyfp) fclose(keyfp); + if (cms) free(cms); + if (in) free(in); + return ret; +} diff --git a/tools/cmsverify.c b/tools/cmsverify.c new file mode 100644 index 00000000..739131e5 --- /dev/null +++ b/tools/cmsverify.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2021 - 2021 The GmSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the GmSSL Project. + * (http://gmssl.org/)" + * + * 4. The name "GmSSL Project" must not be used to endorse or promote + * products derived from this software without prior written + * permission. For written permission, please contact + * guanzhi1980@gmail.com. + * + * 5. Products derived from this software may not be called "GmSSL" + * nor may "GmSSL" appear in their names without prior written + * permission of the GmSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the GmSSL Project + * (http://gmssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE GmSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE GmSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + + +static const char *options = "-in file [-out file]"; + +int cmsverify_main(int argc, char **argv) +{ + int ret = 1; + char *prog = argv[0]; + char *infile = NULL; + char *outfile = NULL; + FILE *infp = NULL; + FILE *outfp = NULL; + struct stat st; + uint8_t *cms = NULL; + size_t cmslen, cms_maxlen; + + int content_type; + const uint8_t *content; + size_t content_len; + const uint8_t *certs; + size_t certslen; + const uint8_t *crls; + size_t crlslen; + const uint8_t *signer_infos; + size_t signer_infos_len; + int rv; + + argc--; + argv++; + + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 1) { + if (!strcmp(*argv, "-help")) { + printf("usage: %s %s\n", prog, options); + ret = 0; + goto end; + } else if (!strcmp(*argv, "-in")) { + if (--argc < 1) goto bad; + infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } + } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; +bad: + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; + } + + argc--; + argv++; + } + + if (!infile) { + fprintf(stderr, "%s: '-in' option required\n", prog); + goto end; + } + fstat(fileno(infp), &st); + cms_maxlen = (st.st_size * 3)/4 + 1; + if (!(cms = malloc(cms_maxlen))) { + fprintf(stderr, "%s: malloc failure\n", prog); + goto end; + } + if (cms_from_pem(cms, &cmslen, cms_maxlen, infp) != 1) { + fprintf(stderr, "%s: read CMS failure\n", prog); + goto end; + } + + if ((rv = cms_verify(cms, cmslen, NULL, 0, NULL, 0, + &content_type, &content, &content_len, + &certs, &certslen, &crls, &crlslen, + &signer_infos, &signer_infos_len)) < 0) { + fprintf(stderr, "%s: verify error\n", prog); + goto end; + } + printf("verify %s\n", rv ? "success" : "failure"); + ret = rv ? 0 : 1; + + if (outfile) { + const uint8_t *p; + size_t len; + + if (content_type == OID_cms_data) { + if (asn1_octet_string_from_der(&p, &len, &content, &content_len) != 1 + || asn1_length_is_zero(content_len) != 1) { + fprintf(stderr, "%s: invalid CMS\n", prog); + goto end; + } + if (len != fwrite(p, 1, len, outfp)) { + fprintf(stderr, "%s: output error : %s\n", prog, strerror(errno)); + goto end; + } + } else { + fprintf(stderr, "%s: error\n", prog); + goto end; + } + + } + + + +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + if (cms) free(cms); + return ret; +} diff --git a/tools/crlparse.c b/tools/crlparse.c index 1f284836..bbae4748 100644 --- a/tools/crlparse.c +++ b/tools/crlparse.c @@ -47,22 +47,24 @@ */ #include +#include #include #include -#include #include #include -#include -static const char *options = "[-in file]"; + +static const char *options = "[-in file] [-out file]"; int crlparse_main(int argc, char **argv) { + int ret = 1; char *prog = argv[0]; char *infile = NULL; + char *outfile = NULL; FILE *infp = stdin; - - uint8_t crl[18192]; + FILE *outfp = stdout; + uint8_t crl[64 * 1024]; size_t crllen; argc--; @@ -71,38 +73,50 @@ int crlparse_main(int argc, char **argv) while (argc > 0) { if (!strcmp(*argv, "-help")) { printf("usage: %s %s\n", prog, options); - return 0; + goto end; } else if (!strcmp(*argv, "-in")) { if (--argc < 1) goto bad; infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; bad: - fprintf(stderr, "%s: llegal option '%s'\n", prog, *argv); - printf("usage: %s %s\n", prog, options); - return 1; + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; } argc--; argv++; } - if (infile) { - if (!(infp = fopen(infile, "r"))) { - error_print(); - return -1; + for (;;) { + int rv; + + if ((rv = x509_crl_from_fp(crl, &crllen, sizeof(crl), infp)) != 1) { + if (rv < 0) fprintf(stderr, "%s: read CRL failure\n", prog); + else ret = 0; + goto end; + } + x509_crl_print(outfp, 0, 0, "CRL", crl, crllen); + if (x509_crl_to_pem(crl, crllen, outfp) != 1) { + fprintf(stderr, "%s: output CRL failure\n", prog); + goto end; } } - for (;;) { - int ret; - if ((ret = x509_crl_from_pem(crl, &crllen, sizeof(crl), infp)) < 0) { - error_print(); - return -1; - } else if (!ret) { - break; - } - x509_crl_print(stdout, 0, 0, "CRL", crl, crllen); - // x509_crl_to_pem(crl, crllen, stdout); - } - return 0; +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + return ret; } diff --git a/tools/gmssl.c b/tools/gmssl.c index b6750f3b..67004a5c 100644 --- a/tools/gmssl.c +++ b/tools/gmssl.c @@ -76,6 +76,11 @@ extern int sm9sign_main(int argc, char **argv); extern int sm9verify_main(int argc, char **argv); extern int sm9encrypt_main(int argc, char **argv); extern int sm9decrypt_main(int argc, char **argv); +extern int cmsparse_main(int argc, char **argv); +extern int cmsencrypt_main(int argc, char **argv); +extern int cmsdecrypt_main(int argc, char **argv); +extern int cmssign_main(int argc, char **argv); +extern int cmsverify_main(int argc, char **argv); extern int tlcp_client_main(int argc, char **argv); extern int tlcp_server_main(int argc, char **argv); extern int tls12_client_main(int argc, char **argv); @@ -90,18 +95,18 @@ static const char *options = "command [options]\n" "\n" "Commands:\n" - " help Print commands list or help for one command\n" + " help Print this help message\n" " version Print version\n" " rand Generate random bytes\n" " sm2keygen Generate SM2 keypair\n" " sm2sign Generate SM2 signature\n" " sm2verify Verify SM2 signature\n" - " sm2encrypt SM2 public key encryption\n" - " sm2decrypt SM2 decryption\n" + " sm2encrypt Encrypt with SM2 public key\n" + " sm2decrypt Decrypt with SM2 private key\n" " sm3 Generate SM3 hash\n" - " sm3hmac Generate HMAC-SM3 MAC tag\n" - " sm4 Encrypt or decrypt data with SM4\n" - " zuc Encrypt or decrypt data with ZUC\n" + " sm3hmac Generate SM3 HMAC tag\n" + " sm4 Encrypt or decrypt with SM4\n" + " zuc Encrypt or decrypt with ZUC\n" " sm9setup Generate SM9 master secret\n" " sm9keygen Generate SM9 private key\n" " sm9sign Generate SM9 signature\n" @@ -109,21 +114,26 @@ static const char *options = " sm9encrypt SM9 public key encryption\n" " sm9decrypt SM9 decryption\n" " pbkdf2 Generate key from password\n" - " reqgen Generate PKCS #10 certificate signing request (CSR)\n" - " reqsign Generate a certificate from PKCS #10 CSR\n" - " reqparse Parse and print a PKCS #10 CSR\n" + " reqgen Generate certificate signing request (CSR)\n" + " reqsign Generate certificate from CSR\n" + " reqparse Parse and print a CSR\n" " crlparse Parse and print CRL\n" - " certgen Generate a self-signed X.509 certificate in PEM format\n" - " certparse Parse and print certificates in a PEM file\n" - " certverify Verify certificate chain in a PEM file\n" + " certgen Generate a self-signed certificate\n" + " certparse Parse and print certificates\n" + " certverify Verify certificate chain\n" + " cmsparse Parse cryptographic message syntax (CMS)\n" + " cmsencrypt Generate CMS EnvelopedData\n" + " cmsdecrypt Decrypt CMS EnvelopedData\n" + " cmssign Generate CMS SignedData\n" + " cmsverify Verify CMS SignedData\n" + " sdfutil SDF crypto device utility\n" + " skfutil SKF crypto device utility\n" " tlcp_client TLCP client\n" " tlcp_server TLCP server\n" " tls12_client TLS 1.2 client\n" " tls12_server TLS 1.2 server\n" " tls13_client TLS 1.3 client\n" - " tls13_server TLS 1.3 server\n" - " sdfutil SDF crypto device utility\n" - " skfutil SKF crypto device utility\n"; + " tls13_server TLS 1.3 server\n"; @@ -154,6 +164,8 @@ int main(int argc, char **argv) return certparse_main(argc, argv); } else if (!strcmp(*argv, "certverify")) { return certverify_main(argc, argv); + } else if (!strcmp(*argv, "crlparse")) { + return crlparse_main(argc, argv); } else if (!strcmp(*argv, "reqgen")) { return reqgen_main(argc, argv); } else if (!strcmp(*argv, "reqparse")) { @@ -192,6 +204,16 @@ int main(int argc, char **argv) return sm9encrypt_main(argc, argv); } else if (!strcmp(*argv, "sm9decrypt")) { return sm9decrypt_main(argc, argv); + } else if (!strcmp(*argv, "cmsparse")) { + return cmsparse_main(argc, argv); + } else if (!strcmp(*argv, "cmsencrypt")) { + return cmsencrypt_main(argc, argv); + } else if (!strcmp(*argv, "cmsdecrypt")) { + return cmsdecrypt_main(argc, argv); + } else if (!strcmp(*argv, "cmssign")) { + return cmssign_main(argc, argv); + } else if (!strcmp(*argv, "cmsverify")) { + return cmsverify_main(argc, argv); } else if (!strcmp(*argv, "tlcp_client")) { return tlcp_client_main(argc, argv); } else if (!strcmp(*argv, "tlcp_server")) { diff --git a/tools/reqgen.c b/tools/reqgen.c index 388b33a8..b6acda50 100644 --- a/tools/reqgen.c +++ b/tools/reqgen.c @@ -47,28 +47,23 @@ */ #include +#include #include #include -#include +#include +#include +#include #include #include -#include -#include -#include -#ifndef WIN32 -#include -#include -#endif - static const char *options = "[-C str] [-ST str] [-L str] [-O str] [-OU str] -CN str -days num" " -key file [-pass pass] [-out file]"; int reqgen_main(int argc, char **argv) { - int ret = -1; + int ret = 1; char *prog = argv[0]; char *country = NULL; char *state = NULL; @@ -76,34 +71,31 @@ int reqgen_main(int argc, char **argv) char *org = NULL; char *org_unit = NULL; char *common_name = NULL; - - char *file = NULL; - char *pass = NULL; int days = 0; - - FILE *keyfp = NULL; - FILE *outfp = stdout; - - uint8_t req[1024]; - size_t reqlen = 0; - + char *keyfile = NULL; + char *pass = NULL; + char *outfile = NULL; uint8_t name[256]; size_t namelen = 0; - - SM2_KEY sm2_key; // 这个应该是从文件中读取的! - - if (argc < 2) { - fprintf(stderr, "usage: %s %s\n", prog, options); - return 1; - } + FILE *keyfp = NULL; + FILE *outfp = stdout; + uint8_t req[1024]; + size_t reqlen = 0; + SM2_KEY sm2_key; argc--; argv++; - while (argc >= 1) { + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); + return 1; + } + + while (argc > 0) { if (!strcmp(*argv, "-help")) { printf("usage: %s %s\n", prog, options); - return 0; + ret = 0; + goto end; } else if (!strcmp(*argv, "-C")) { if (--argc < 1) goto bad; country = *(++argv); @@ -122,51 +114,62 @@ int reqgen_main(int argc, char **argv) } else if (!strcmp(*argv, "-CN")) { if (--argc < 1) goto bad; common_name = *(++argv); + } else if (!strcmp(*argv, "-days")) { + if (--argc < 1) goto bad; + days = atoi(*(++argv)); + if (days <= 0) { + fprintf(stderr, "%s: invalid '-days' value\n", prog); + goto end; + } } else if (!strcmp(*argv, "-key")) { if (--argc < 1) goto bad; - file = *(++argv); - if (!(keyfp = fopen(file, "r"))) { - error_print(); - return -1; + keyfile = *(++argv); + if (!(keyfp = fopen(keyfile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno)); + goto end; } } else if (!strcmp(*argv, "-pass")) { if (--argc < 1) goto bad; pass = *(++argv); - } else if (!strcmp(*argv, "-days")) { - if (--argc < 1) goto bad; - days = atoi(*(++argv)); } else if (!strcmp(*argv, "-out")) { if (--argc < 1) goto bad; - file = *(++argv); - if (!(outfp = fopen(file, "w"))) { - error_print(); - return -1; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; } } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; bad: - fprintf(stderr, "usage: %s %s\n", prog, options); + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; } argc--; argv++; } - if (!common_name || days <= 0 || !keyfp) { - fprintf(stderr, "%s: missing options\n", prog); - fprintf(stderr, "usage: %s %s\n", prog, options); - return 1; + if (!common_name) { + fprintf(stderr, "%s: '-CN' option required\n", prog); + goto end; + } + if (!days) { + fprintf(stderr, "%s: '-days' option required\n", prog); + goto end; + } + if (!keyfile) { + fprintf(stderr, "%s: '-key' option required\n", prog); + goto end; } if (!pass) { - pass = getpass("Encryption Password : "); - } - if (!pass || strlen(pass) == 0) { fprintf(stderr, "%s: '-pass' option required\n", prog); - error_print(); - return -1; + goto end; } + if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) { - error_print(); - return -1; + fprintf(stderr, "%s: load private key failed\n", prog); + goto end; } if (x509_name_set(name, &namelen, sizeof(name), @@ -177,13 +180,18 @@ bad: &sm2_key, NULL, 0, OID_sm2sign_with_sm3, - &sm2_key, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1 - || x509_req_to_pem(req, reqlen, outfp) != 1) { - memset(&sm2_key, 0, sizeof(SM2_KEY)); - error_print(); - return -1; + &sm2_key, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; } - - memset(&sm2_key, 0, sizeof(SM2_KEY)); - return 0; + if (x509_req_to_pem(req, reqlen, outfp) != 1) { + fprintf(stderr, "%s: output CSR failed\n", prog); + goto end; + } + ret = 0; +end: + gmssl_secure_clear(&sm2_key, sizeof(SM2_KEY)); + if (keyfp) fclose(keyfp); + if (outfile && outfp) fclose(outfp); + return ret; } diff --git a/tools/reqparse.c b/tools/reqparse.c index 6363d0f3..6e048da7 100644 --- a/tools/reqparse.c +++ b/tools/reqparse.c @@ -47,19 +47,23 @@ */ #include +#include #include #include -#include #include #include -#include +static const char *options = "[-in file] [-out file]"; + int reqparse_main(int argc, char **argv) { + int ret = 1; char *prog = argv[0]; char *infile = NULL; + char *outfile = NULL; FILE *infp = stdin; + FILE *outfp = stdout; uint8_t req[1024]; size_t reqlen; @@ -68,39 +72,46 @@ int reqparse_main(int argc, char **argv) while (argc > 0) { if (!strcmp(*argv, "-help")) { -help: - fprintf(stderr, "usage: %s [-in file]\n", prog); - return -1; - + printf("usage: %s %s\n", prog, options); + goto end; } else if(!strcmp(*argv, "-in")) { if (--argc < 1) goto bad; infile = *(++argv); - + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, infile, strerror(errno)); + goto end; + } + } else if (!strcmp(*argv, "-out")) { + if (--argc < 1) goto bad; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; + } } else { fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); - goto help; + goto end; +bad: + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; } argc--; argv++; } - if (infile) { - if (!(infp = fopen(infile, "r"))) { - error_print(); - return -1; - } - } - if (x509_req_from_pem(req, &reqlen, sizeof(req), infp) != 1) { - error_print(); - return -1; + fprintf(stderr, "%s: read CSR failure\n", prog); + goto end; } - x509_req_print(stdout, 0, 0, "CertificationRequest", req, reqlen); - x509_req_to_pem(req, reqlen, stdout); - return 0; - -bad: - fprintf(stderr, "%s: '%s' option value required\n", prog, *argv); - return -1; + x509_req_print(outfp, 0, 0, "CertificationRequest", req, reqlen); + if (x509_req_to_pem(req, reqlen, outfp) != 1) { + fprintf(stderr, "%s: output CSR failure\n", prog); + goto end; + } + ret = 0; +end: + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + return ret; } diff --git a/tools/reqsign.c b/tools/reqsign.c index 49dc3d08..5e64b177 100644 --- a/tools/reqsign.c +++ b/tools/reqsign.c @@ -47,43 +47,42 @@ */ #include +#include #include #include -#include -#include +#include +#include #include #include #include -#include -#include -#include + + +static const char *options = "[-in pem] -days num -cacert pem -key pem [-pass str] [-out pem]\n"; static int ext_key_usage_set(int *usages, const char *usage_name) { int flag = 0; if (x509_key_usage_from_name(&flag, usage_name) != 1) { - error_print(); return -1; } *usages |= flag; - - printf("flag = %08x", flag); - printf("usage = %08x", *usages); return 1; } - -static const char *usage = "usage: %s [-in file] -days num -cacert file -key file [-pass str] [-out file]\n"; - int reqsign_main(int argc, char **argv) { + int ret = 1; char *prog = argv[0]; - char *file; - char *pass = NULL; + char *infile = NULL; int days = 0; - + char *cacertfile = NULL; + char *keyfile = NULL; + char *pass = NULL; + char *outfile = NULL; FILE *infp = stdin; - + FILE *cacertfp = NULL; + FILE *keyfp = NULL; + FILE *outfp = stdout; uint8_t req[512]; size_t reqlen; @@ -91,16 +90,12 @@ int reqsign_main(int argc, char **argv) size_t subject_len; SM2_KEY subject_public_key; - FILE *outfp = stdout; - - FILE *cacertfp = NULL; uint8_t cacert[1024]; size_t cacertlen; const uint8_t *issuer; size_t issuer_len; SM2_KEY issuer_public_key; - FILE *keyfp = NULL; SM2_KEY sm2_key; uint8_t cert[1024]; @@ -111,107 +106,121 @@ int reqsign_main(int argc, char **argv) size_t extslen = 0; int key_usage = 0; + argc--; + argv++; - if (argc < 2) { - fprintf(stderr, usage, prog); + if (argc < 1) { + fprintf(stderr, "usage: %s %s\n", prog, options); return 1; } - argc--; - argv++; while (argc >= 1) { if (!strcmp(*argv, "-help")) { -help: - printf(usage, prog); - return 0; + printf("usage: %s %s\n", prog, options); + ret = 0; + goto end; } else if (!strcmp(*argv, "-in")) { if (--argc < 1) goto bad; - file = *(++argv); - if (!(infp = fopen(file, "r"))) { - error_print(); - return -1; + infile = *(++argv); + if (!(infp = fopen(infile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; } } else if (!strcmp(*argv, "-days")) { if (--argc < 1) goto bad; days = atoi(*(++argv)); + if (days <= 0) { + fprintf(stderr, "%s: invalid '-days' value\n", prog); + goto end; + } } else if (!strcmp(*argv, "-key_usage")) { if (--argc < 1) goto bad; if (ext_key_usage_set(&key_usage, *(++argv)) != 1) { - error_print(); - return -1; + fprintf(stderr, "%s: set KeyUsage extenstion failure\n", prog); + goto end; } } else if (!strcmp(*argv, "-cacert")) { if (--argc < 1) goto bad; - file = *(++argv); - if (!(cacertfp = fopen(file, "r"))) { - error_print(); - return -1; + cacertfile = *(++argv); + if (!(cacertfp = fopen(cacertfile, "r"))) { + fprintf(stderr, "%s: invalid -key_usage value\n", prog); + goto end; } } else if (!strcmp(*argv, "-key")) { if (--argc < 1) goto bad; - file = *(++argv); - if (!(keyfp = fopen(file, "r"))) { - error_print(); - return -1; + keyfile = *(++argv); + if (!(keyfp = fopen(keyfile, "r"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, keyfile, strerror(errno)); + goto end; } } else if (!strcmp(*argv, "-pass")) { if (--argc < 1) goto bad; pass = *(++argv); - } else if (!strcmp(*argv, "-out")) { if (--argc < 1) goto bad; - file = *(++argv); - if (!(outfp = fopen(file, "w"))) { - error_print(); - return -1; + outfile = *(++argv); + if (!(outfp = fopen(outfile, "w"))) { + fprintf(stderr, "%s: open '%s' failure : %s\n", prog, outfile, strerror(errno)); + goto end; } } else { + fprintf(stderr, "%s: illegal option '%s'\n", prog, *argv); + goto end; bad: - error_print(); - break; + fprintf(stderr, "%s: '%s' option value missing\n", prog, *argv); + goto end; } argc--; argv++; } - if (days <= 0 - || !infp - || !cacertfp - || !keyfp) { - error_print(); - return -1; + + if (!days) { + fprintf(stderr, "%s: '-days' option required\n", prog); + goto end; } + if (!cacertfile) { + fprintf(stderr, "%s: '-cacert' option required\n", prog); + goto end; + } + if (!keyfile) { + fprintf(stderr, "%s: '-key' option required\n", prog); + goto end; + } + if (!pass) { + fprintf(stderr, "%s: '-pass' option required\n", prog); + goto end; + } + if (x509_req_from_pem(req, &reqlen, sizeof(req), infp) != 1 || x509_req_get_details(req, reqlen, NULL, &subject, &subject_len, &subject_public_key, NULL, NULL, NULL, NULL, NULL) != 1) { - error_print(); - return -1; + fprintf(stderr, "%s: parse CSR failure\n", prog); + goto end; } if (x509_cert_from_pem(cacert, &cacertlen, sizeof(cacert), cacertfp) != 1 || x509_cert_get_subject(cacert, cacertlen, &issuer, &issuer_len) != 1 || x509_cert_get_subject_public_key(cacert, cacertlen, &issuer_public_key) != 1) { - error_print(); - return -1; + fprintf(stderr, "%s: parse CA certificate failure\n", prog); + goto end; } - if (!pass) { - pass = getpass("Password : "); + if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1) { + fprintf(stderr, "%s: load private key failure\n", prog); + goto end; } - if (!pass || strlen(pass) == 0) { - error_print(); - return -1; - } - if (sm2_private_key_info_decrypt_from_pem(&sm2_key, pass, keyfp) != 1 - || sm2_public_key_equ(&sm2_key, &issuer_public_key) != 1) { - error_print(); - memset(&sm2_key, 0, sizeof(SM2_KEY)); - return -1; + if (sm2_public_key_equ(&sm2_key, &issuer_public_key) != 1) { + fprintf(stderr, "%s: private key and CA certificate not match\n", prog); + goto end; } - rand_bytes(serial, sizeof(serial)); + if (rand_bytes(serial, sizeof(serial)) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; + } time(¬_before); if (x509_validity_add_days(¬_after, not_before, days) != 1 @@ -228,14 +237,20 @@ bad: NULL, 0, NULL, 0, exts, extslen, - &sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1 - || x509_cert_to_pem(cert, certlen, outfp) != 1) { - memset(&sm2_key, 0, sizeof(SM2_KEY)); - error_print(); - return -1; + &sm2_key, SM2_DEFAULT_ID, SM2_DEFAULT_ID_LENGTH) != 1) { + fprintf(stderr, "%s: inner error\n", prog); + goto end; } - - // FIXME: fclose() .... - memset(&sm2_key, 0, sizeof(SM2_KEY)); - return 0; + if (x509_cert_to_pem(cert, certlen, outfp) != 1) { + fprintf(stderr, "%s: output certificate failed\n", prog); + goto end; + } + ret = 0; +end: + gmssl_secure_clear(&sm2_key, sizeof(SM2_KEY)); + if (keyfp) fclose(keyfp); + if (cacertfp) fclose(cacertfp); + if (infile && infp) fclose(infp); + if (outfile && outfp) fclose(outfp); + return ret; } diff --git a/tools/sm2decrypt.c b/tools/sm2decrypt.c index dc005172..75327b7d 100644 --- a/tools/sm2decrypt.c +++ b/tools/sm2decrypt.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) 2021 - 2021 The GmSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -131,7 +131,7 @@ bad: } if (sm2_private_key_info_decrypt_from_pem(&key, pass, keyfp) != 1) { - fprintf(stderr, "%s: private key decryption failure", prog); + fprintf(stderr, "%s: private key decryption failure\n", prog); goto end; }