1/*
2 * Copyright (c) 2024-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15#ifndef SIGNATRUETOOLS_PKCS7DATA_H
16#define SIGNATRUETOOLS_PKCS7DATA_H
17
18#include <fstream>
19#include <string>
20#include <vector>
21#include <memory>
22#include <algorithm>
23#include <unordered_set>
24#include <algorithm>
25#include <list>
26
27#include "openssl/pem.h"
28#include "openssl/ecdsa.h"
29#include "openssl/evp.h"
30#include "openssl/ec.h"
31#include "openssl/asn1t.h"
32#include "openssl/pkcs7.h"
33#include "signer.h"
34#include "verify_cert_openssl_utils.h"
35
36 /* compare cert is equal in std::unordered_set<X509*> for SortX509Stack */
37template<>
38struct std::equal_to<X509*> {
39    bool operator() (X509* cert1, X509* cert2) const
40    {
41        ASN1_INTEGER* serial1 = X509_get_serialNumber(cert1);
42        ASN1_INTEGER* serial2 = X509_get_serialNumber(cert2);
43        bool serialEqual = ASN1_INTEGER_cmp(serial1, serial2) == 0;
44        bool nameEqual = X509_NAME_cmp(X509_get_subject_name(cert1), X509_get_subject_name(cert2)) == 0;
45        return serialEqual && nameEqual;
46    }
47};
48
49/* all cert is put into one bottle */
50template<>
51struct std::hash<X509*> {
52    size_t operator()(const X509* cert) const
53    {
54        return 0;
55    }
56};
57
58namespace OHOS {
59namespace SignatureTools {
60#define  PKCS7_NODETACHED_FLAGS  (PKCS7_BINARY | PKCS7_NOVERIFY)
61#define  PKCS7_DETACHED_FLAGS    (PKCS7_BINARY | PKCS7_NOVERIFY | PKCS7_DETACHED)
62struct PKCS7Attr {
63    int nid;
64    int atrtype;
65    void* value;
66};
67
68class PKCS7Data {
69public:
70    PKCS7Data(int flags = PKCS7_NODETACHED_FLAGS);
71    PKCS7Data(const PKCS7Data& pkcs7) = delete;
72    const PKCS7Data& operator=(const PKCS7Data& pkcs7) = delete;
73    ~PKCS7Data();
74    /*
75    * @param content The data to be signed
76    * @param signer  signer
77    * @param sigAlg  Signature algorithm SHA256withECDSA/SHA384withECDSA
78    * @param ret     The returned signature result is pkcs7
79    * @param attrs   It is only used when you need to add an ownerID, and you don't need to process it by default
80    * @return        0 :success <0 :error
81    */
82    int Sign(const std::string& content, const std::shared_ptr<Signer>& signer, const std::string& sigAlg,
83             std::string& ret, std::vector<PKCS7Attr> attrs = std::vector<PKCS7Attr>());
84    /* d2i deserialize */
85    int Parse(const std::string& p7bBytes);
86    int Parse(const std::vector<int8_t>& p7bBytes);
87    /* When verifying the signature, you don't need to enter content by default, if the data is separated
88     * (content is not in pkcs7, you need to pass in the original data for verification)
89     */
90    int Verify(const std::string& content = "")const;
91    /* get original raw content*/
92    int GetContent(std::string& content) const;
93
94    /* In C++, the certificate chain order is forward, and Java is reversed,
95    which is historically the result of correcting the certificate chain order */
96    static int SortX509Stack(STACK_OF(X509)* certs);
97    /* Subject information for printing the certificate chain */
98    static void PrintCertChainSub(const STACK_OF(X509)* certs);
99    static std::string GetASN1Time(const ASN1_TIME* tm);
100    /* Compare the two, first certificate issuers with the second certificate subject info */
101    static bool X509NameCompare(const X509* cert, const X509* issuerCert);
102    /* check pkcs7 sign time in certchain valid period */
103    static int CheckSignTimeInValidPeriod(const ASN1_TYPE* signTime,
104                                          const ASN1_TIME* notBefore, const ASN1_TIME* notAfter);
105
106private:
107    int Parse(const unsigned char** in, long len);
108    int InitPkcs7(const std::string& content, const std::shared_ptr<Signer>& signer,
109                  const std::string& sigAlg, std::vector<PKCS7Attr> attrs);
110    /* Verify Signature Value The certificate chain is not verified here */
111    int VerifySign(const std::string& content)const;
112    int VerifyCertChain()const;
113    /* Verify the validity of the time */
114    int CheckSginerInfoSignTimeInCertChainValidPeriod(PKCS7_SIGNER_INFO* signerInfo, STACK_OF(X509)* certs)const;
115    /* @param cert Entity Certificate
116     * @param certs Certificate chain (without Entity certificates)
117     * @param certChain Certificate chain (with Entity certificates)
118     * @retrun 0 success <0 error
119     */
120    int VerifySignerInfoCertchain(PKCS7* p7,
121                                  PKCS7_SIGNER_INFO* signerInfo,
122                                  STACK_OF(X509)* certs,
123                                  STACK_OF(X509)* certChain)const;
124
125private:
126    /* For ease of reading, the following interface will be as consistent as possible with the OpenSSL
127    library interface style, and the return value is 1 success and 0 failure */
128    int Pkcs7SignAttr(PKCS7_SIGNER_INFO* si);
129
130    int Pkcs7AddTimeDigestAndSignAttr(PKCS7_SIGNER_INFO* si, EVP_MD_CTX* mctx);
131
132    int Pkcs7DataFinalSignAttr(STACK_OF(PKCS7_SIGNER_INFO)* si_sk, BIO* bio);
133
134    int Pkcs7DataFinal(PKCS7* p7, BIO* bio);
135
136    int Pkcs7Final(PKCS7* p7, const std::string& content, int flags);
137
138    PKCS7* Pkcs7Sign(X509* signcert, STACK_OF(X509)* certs, const EVP_MD* md,
139                     const std::string& content, int flags, const std::vector<PKCS7Attr>& attrs);
140
141private:
142    PKCS7* m_p7 = NULL;
143    int m_flags;
144    std::shared_ptr<Signer> m_signer; // tmp
145    std::string m_sigAlg; // tmp
146};
147} // namespace SignatureTools
148} // namespace OHOS
149#endif // SIGNATRUETOOLS_PKCS7DATA_H