OpenSSL解析X509证书

前言

网上搜索出来的OpenSSL解析证书很多都是命令行工具的操作,还有一些C++实现的,用的版本的比较老,很多接口都变了。整理了基于OpenSSL1.11版本解析X509证书的实现。

接口

参照QSslCertificate接口,基于标准C++实现类似的接口,不依赖Qt,支持RSA和SM2证书信息解析,解析PFX、P7B证书、解析证书链、验证书等

具体接口如下:

#ifndef X509CERTIFICATE_H
#define X509CERTIFICATE_H

#include <string>
#include <vector>
#include <map>
#include <memory>

#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
#  define Q_DECL_EXPORT __declspec(dllexport)
#  define Q_DECL_IMPORT __declspec(dllimport)
#else
#  define Q_DECL_EXPORT     __attribute__((visibility("default")))
#  define Q_DECL_IMPORT     __attribute__((visibility("default")))
#endif

#if defined(X509CERTIFICATE_LIBRARY)
#  define X509CERTIFICATE_EXPORT Q_DECL_EXPORT
#else
#  define X509CERTIFICATE_EXPORT Q_DECL_IMPORT
#endif

using namespace std;

class X509Certificate_p;
class X509CertificateExtension;
class X509CertificateExtension_p;
class X509CERTIFICATE_EXPORT X509Certificate
{
public:
    X509Certificate();
    X509Certificate(const char *cert, int len);
    X509Certificate(const X509Certificate &other);

    enum HashType {
        Hash_Sha1,
        Hash_Sha256,
        Hash_SM3
    };

    enum SubjectInfo {
        Organization,
        CommonName,
        LocalityName,
        OrganizationalUnitName,
        CountryName,
        StateOrProvinceName,
        DistinguishedNameQualifier,
        SerialNumber,
        EmailAddress
    };

    X509Certificate &operator=(const X509Certificate &other);

    bool operator==(const X509Certificate &other) const;
    inline bool operator!=(const X509Certificate &other) const { return !operator==(other); }

    bool isNull() const;
    void *handle() const;

    int version() const;
    string serialNumber() const;

    string subject() const;
    string subjectInfo(SubjectInfo subject) const;
    string subjectDisplyName() const;

    string issuer() const;
    string issuerInfo(SubjectInfo issuer) const;
    string issuerDisplyName() const;

    string notBefor() const;
    string notAfter() const;

    string digest(HashType type) const;

    string publicKeyValue() const;
    string publicKeyType() const;

    string signAlgType() const;
    string signValue() const;

    vector<X509CertificateExtension> extensions() const;

    string toDer() const;
    string toPem() const;
    string toText() const;

    static bool importPkcs12(const char *pfxFile, int len, char *priKey, int &priKeyLen,
                            X509Certificate *x509Cert, vector<X509Certificate> &caCerts,
                            const char *pass = "");
    static bool importP7b(const char *p7b, int len, vector<X509Certificate> &caCerts);

    static vector<X509Certificate *> splitCertChain(const string &chains);//only pem

    static int verify(const X509Certificate &userCert, vector<X509Certificate> certificateChain);

    static vector<X509Certificate> systemCaCertificates();
private:
    shared_ptr<X509Certificate_p> p;
    friend class X509Certificate_p;
};



class X509CERTIFICATE_EXPORT X509CertificateExtension
{
public:
    X509CertificateExtension();

    enum ExtMethod {
        Ext_String,
        Ext_Vector,
        Ext_Map
    };

    bool isCritical() const;
    bool isSupported() const;
    string name() const;
    string oid() const;
    string value() const;

    ExtMethod methodType() const;
    string toString() const;
    vector<string> toVector() const;
    multimap<string, string> toMap() const;

private:
    X509CertificateExtension_p *p = nullptr;

    friend class X509Certificate;
};

#endif // X509CERTIFICATE_H

具体的代码实放在github上,这里,整个项目包含一个测试接口的工程和生成共享库的工程,都是Qt工程,当然实现的源码是不依赖Qt,构建其他工程也是可以的。

OpenSSL依赖版本Windows下已提供,默认使用的是静态链接,因为OpenSSL实在是太庞大了,X509只是其中很小的一部分,静态链接的方式会好些。Linux下的需要安装libssl-dev包,采用动态链接的方式,要用静态链接得自己编译了,Windows是因为有现成的库。测试了Windows和Linux下都是能够正常使用的,理论上只要OpenSSL能够使用,其他平台都能够使用,这就需要另外去测试了。

整个接口构造参照Qt的p指针和q指针的方式,即实现的类和接口类是分开的,希望能满足C++的二进制兼容,具体并没有去测试。

结语

最后,自己水平有限,不论是代码结构还是代码实现,其中或多或少都会有问题,欢迎各位大佬指正

上一篇:openssl各种文件类型说明


下一篇:解决docker:x509:certificate has expired or is not yet valid