欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OpenSSL解析X509证书

程序员文章站 2022-07-12 22:08:40
...

前言

网上搜索出来的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++的二进制兼容,具体并没有去测试。

结语

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