github.com/emmansun/gmsm@v0.29.1/pkcs7/verify.go (about) 1 package pkcs7 2 3 import ( 4 "crypto/subtle" 5 "crypto/x509" 6 "crypto/x509/pkix" 7 "encoding/asn1" 8 "errors" 9 "fmt" 10 "time" 11 12 "github.com/emmansun/gmsm/smx509" 13 ) 14 15 // Verify is a wrapper around VerifyWithChain() that initializes an empty 16 // trust store, effectively disabling certificate verification when validating 17 // a signature. 18 func (p7 *PKCS7) Verify() (err error) { 19 return p7.VerifyWithChain(nil) 20 } 21 22 // VerifyWithChain checks the signatures of a PKCS7 object. 23 // 24 // If truststore is not nil, it also verifies the chain of trust of 25 // the end-entity signer cert to one of the roots in the 26 // truststore. When the PKCS7 object includes the signing time 27 // authenticated attr verifies the chain at that time and UTC now 28 // otherwise. 29 func (p7 *PKCS7) VerifyWithChain(truststore *smx509.CertPool) (err error) { 30 if len(p7.Signers) == 0 { 31 return errors.New("pkcs7: Message has no signers") 32 } 33 for _, signer := range p7.Signers { 34 if err := verifySignature(p7, signer, truststore, nil); err != nil { 35 return err 36 } 37 } 38 return nil 39 } 40 41 // VerifyWithChainAtTime checks the signatures of a PKCS7 object. 42 // 43 // If truststore is not nil, it also verifies the chain of trust of 44 // the end-entity signer cert to a root in the truststore at 45 // currentTime. It does not use the signing time authenticated 46 // attribute. 47 func (p7 *PKCS7) VerifyWithChainAtTime(truststore *smx509.CertPool, currentTime *time.Time) (err error) { 48 if len(p7.Signers) == 0 { 49 return errors.New("pkcs7: Message has no signers") 50 } 51 for _, signer := range p7.Signers { 52 if err := verifySignature(p7, signer, truststore, currentTime); err != nil { 53 return err 54 } 55 } 56 return nil 57 } 58 59 func verifySignature(p7 *PKCS7, signer signerInfo, truststore *smx509.CertPool, currentTime *time.Time) (err error) { 60 signedData := p7.Content 61 ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) 62 if ee == nil { 63 return errors.New("pkcs7: No certificate for signer") 64 } 65 signingTime := time.Now().UTC() 66 if len(signer.AuthenticatedAttributes) > 0 { 67 // TODO(fullsailor): First check the content type match 68 var digest []byte 69 err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest) 70 if err != nil { 71 return err 72 } 73 hasher, err := getHashForOID(signer.DigestAlgorithm.Algorithm) 74 if err != nil { 75 return err 76 } 77 h := newHash(hasher, signer.DigestAlgorithm.Algorithm) 78 h.Write(p7.Content) 79 computed := h.Sum(nil) 80 if subtle.ConstantTimeCompare(digest, computed) != 1 { 81 return &MessageDigestMismatchError{ 82 ExpectedDigest: digest, 83 ActualDigest: computed, 84 } 85 } 86 signedData, err = marshalAttributes(signer.AuthenticatedAttributes) 87 if err != nil { 88 return err 89 } 90 err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime) 91 if err == nil { 92 // signing time found, performing validity check 93 if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) { 94 return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q", 95 signingTime.Format(time.RFC3339), 96 ee.NotBefore.Format(time.RFC3339), 97 ee.NotAfter.Format(time.RFC3339)) 98 } 99 } 100 } 101 if truststore != nil { 102 if currentTime != nil { 103 signingTime = *currentTime 104 } 105 _, err = verifyCertChain(ee, p7.Certificates, truststore, signingTime) 106 if err != nil { 107 return err 108 } 109 } 110 sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm) 111 if err != nil { 112 return err 113 } 114 return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest) 115 } 116 117 // GetOnlySigner returns an x509.Certificate for the first signer of the signed 118 // data payload. If there are more or less than one signer, nil is returned 119 func (p7 *PKCS7) GetOnlySigner() *smx509.Certificate { 120 if len(p7.Signers) != 1 { 121 return nil 122 } 123 signer := p7.Signers[0] 124 return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) 125 } 126 127 // UnmarshalSignedAttribute decodes a single attribute from the signer info 128 func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out any) error { 129 sd, ok := p7.raw.(signedData) 130 if !ok { 131 return errors.New("pkcs7: payload is not signedData content") 132 } 133 if len(sd.SignerInfos) < 1 { 134 return errors.New("pkcs7: payload has no signers") 135 } 136 attributes := sd.SignerInfos[0].AuthenticatedAttributes 137 return unmarshalAttribute(attributes, attributeType, out) 138 } 139 140 func parseSignedData(data []byte) (*PKCS7, error) { 141 var sd signedData 142 asn1.Unmarshal(data, &sd) 143 certs, err := sd.Certificates.Parse() 144 if err != nil { 145 return nil, err 146 } 147 // fmt.Printf("--> Signed Data Version %d\n", sd.Version) 148 149 var compound asn1.RawValue 150 var content unsignedData 151 152 // The Content.Bytes maybe empty on PKI responses. 153 if len(sd.ContentInfo.Content.Bytes) > 0 { 154 if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil { 155 return nil, err 156 } 157 } 158 // Compound octet string 159 if compound.IsCompound && compound.Tag == 4 { 160 if _, err = asn1.Unmarshal(compound.Bytes, &content); err != nil { 161 return nil, err 162 } 163 } else { 164 // assuming this is tag 04 165 content = compound.Bytes 166 } 167 return &PKCS7{ 168 Content: content, 169 Certificates: certs, 170 CRLs: sd.CRLs, 171 Signers: sd.SignerInfos, 172 raw: sd}, nil 173 } 174 175 // verifyCertChain takes an end-entity certs, a list of potential intermediates and a 176 // truststore, and built all potential chains between the EE and a trusted root. 177 // 178 // When verifying chains that may have expired, currentTime can be set to a past date 179 // to allow the verification to pass. If unset, currentTime is set to the current UTC time. 180 func verifyCertChain(ee *smx509.Certificate, certs []*smx509.Certificate, truststore *smx509.CertPool, currentTime time.Time) (chains [][]*smx509.Certificate, err error) { 181 intermediates := smx509.NewCertPool() 182 for _, intermediate := range certs { 183 intermediates.AddCert(intermediate) 184 } 185 verifyOptions := smx509.VerifyOptions{ 186 Roots: truststore, 187 Intermediates: intermediates, 188 KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, 189 CurrentTime: currentTime, 190 } 191 chains, err = ee.Verify(verifyOptions) 192 if err != nil { 193 return chains, fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err) 194 } 195 return 196 } 197 198 // MessageDigestMismatchError is returned when the signer data digest does not 199 // match the computed digest for the contained content 200 type MessageDigestMismatchError struct { 201 ExpectedDigest []byte 202 ActualDigest []byte 203 } 204 205 func (err *MessageDigestMismatchError) Error() string { 206 return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual : %X", err.ExpectedDigest, err.ActualDigest) 207 } 208 209 func getSignatureAlgorithm(digestEncryption, digest pkix.AlgorithmIdentifier) (x509.SignatureAlgorithm, error) { 210 switch { 211 case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA1): 212 return x509.ECDSAWithSHA1, nil 213 case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA256): 214 return x509.ECDSAWithSHA256, nil 215 case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA384): 216 return x509.ECDSAWithSHA384, nil 217 case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA512): 218 return x509.ECDSAWithSHA512, nil 219 case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSA), 220 digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1), 221 digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256), 222 digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384), 223 digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512): 224 switch { 225 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1): 226 return x509.SHA1WithRSA, nil 227 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256): 228 return x509.SHA256WithRSA, nil 229 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384): 230 return x509.SHA384WithRSA, nil 231 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512): 232 return x509.SHA512WithRSA, nil 233 default: 234 return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q", 235 digest.Algorithm.String(), digestEncryption.Algorithm.String()) 236 } 237 case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSA), 238 digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSASHA1): 239 switch { 240 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1): 241 return x509.DSAWithSHA1, nil 242 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256): 243 return x509.DSAWithSHA256, nil 244 default: 245 return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q", 246 digest.Algorithm.String(), digestEncryption.Algorithm.String()) 247 } 248 case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP256), 249 digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP384), 250 digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP521): 251 switch { 252 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1): 253 return x509.ECDSAWithSHA1, nil 254 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256): 255 return x509.ECDSAWithSHA256, nil 256 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384): 257 return x509.ECDSAWithSHA384, nil 258 case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512): 259 return x509.ECDSAWithSHA512, nil 260 default: 261 return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q", 262 digest.Algorithm.String(), digestEncryption.Algorithm.String()) 263 } 264 case digestEncryption.Algorithm.Equal(OIDDigestEncryptionAlgorithmSM2): 265 return smx509.SM2WithSM3, nil 266 default: 267 return -1, fmt.Errorf("pkcs7: unsupported algorithm %q", 268 digestEncryption.Algorithm.String()) 269 } 270 } 271 272 func getCertFromCertsByIssuerAndSerial(certs []*smx509.Certificate, ias issuerAndSerial) *smx509.Certificate { 273 for _, cert := range certs { 274 if isCertMatchForIssuerAndSerial(cert, ias) { 275 return cert 276 } 277 } 278 return nil 279 } 280 281 func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out any) error { 282 for _, attr := range attrs { 283 if attr.Type.Equal(attributeType) { 284 _, err := asn1.Unmarshal(attr.Value.Bytes, out) 285 return err 286 } 287 } 288 return errors.New("pkcs7: attribute type not in attributes") 289 }