...

Source file src/github.com/sassoftware/relic/lib/authenticode/cabfile.go

Documentation: github.com/sassoftware/relic/lib/authenticode

     1  //
     2  // Copyright (c) SAS Institute Inc.
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  
    17  package authenticode
    18  
    19  import (
    20  	"context"
    21  	"crypto"
    22  	"crypto/hmac"
    23  	"errors"
    24  	"fmt"
    25  	"io"
    26  
    27  	"github.com/sassoftware/relic/lib/binpatch"
    28  	"github.com/sassoftware/relic/lib/cabfile"
    29  	"github.com/sassoftware/relic/lib/certloader"
    30  	"github.com/sassoftware/relic/lib/pkcs7"
    31  	"github.com/sassoftware/relic/lib/pkcs9"
    32  	"github.com/sassoftware/relic/lib/x509tools"
    33  	"github.com/sassoftware/relic/signers/sigerrors"
    34  )
    35  
    36  type CabSignature struct {
    37  	pkcs9.TimestampedSignature
    38  	Indirect *SpcIndirectDataContentPe
    39  	HashFunc crypto.Hash
    40  	PatchSet *binpatch.PatchSet
    41  }
    42  
    43  // Extract and verify the signature of a CAB file. Does not check X509 chains.
    44  func VerifyCab(f io.ReaderAt, skipDigests bool) (*CabSignature, error) {
    45  	cab, err := cabfile.Parse(io.NewSectionReader(f, 0, 1<<63-1))
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	if len(cab.Signature) == 0 {
    50  		return nil, sigerrors.NotSignedError{Type: "cabinet"}
    51  	}
    52  	psd, err := pkcs7.Unmarshal(cab.Signature)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	if !psd.Content.ContentInfo.ContentType.Equal(OidSpcIndirectDataContent) {
    57  		return nil, errors.New("not an authenticode signature")
    58  	}
    59  	pksig, err := psd.Content.Verify(nil, false)
    60  	if err != nil {
    61  		return nil, err
    62  	}
    63  	ts, err := pkcs9.VerifyOptionalTimestamp(pksig)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	indirect := new(SpcIndirectDataContentPe)
    68  	if err := psd.Content.ContentInfo.Unmarshal(indirect); err != nil {
    69  		return nil, err
    70  	}
    71  	hash, err := x509tools.PkixDigestToHashE(indirect.MessageDigest.DigestAlgorithm)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	cabsig := &CabSignature{
    76  		TimestampedSignature: ts,
    77  		Indirect:             indirect,
    78  		HashFunc:             hash,
    79  	}
    80  	if !skipDigests {
    81  		digest, err := cabfile.Digest(io.NewSectionReader(f, 0, 1<<63-1), hash)
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  		if !hmac.Equal(digest.Imprint, indirect.MessageDigest.Digest) {
    86  			return nil, fmt.Errorf("digest mismatch: %x != %x", digest.Imprint, indirect.MessageDigest.Digest)
    87  		}
    88  		// cab signatures seem to come with a "page hash" link in the same way
    89  		// as PE files can, using OidSpcCabPageHash as the type, but it's not
    90  		// clear what it's hashing.
    91  	}
    92  	return cabsig, nil
    93  }
    94  
    95  // Create the Authenticode structure for a CAB file signature using a previously-calculated digest (imprint).
    96  func SignCabImprint(ctx context.Context, digest *cabfile.CabinetDigest, cert *certloader.Certificate) (*binpatch.PatchSet, *pkcs9.TimestampedSignature, error) {
    97  	indirect, err := makePeIndirect(digest.Imprint, digest.HashFunc, OidSpcCabImageData)
    98  	if err != nil {
    99  		return nil, nil, err
   100  	}
   101  	ts, err := signIndirect(ctx, indirect, digest.HashFunc, cert)
   102  	if err != nil {
   103  		return nil, nil, err
   104  	}
   105  	patch := digest.MakePatch(ts.Raw)
   106  	return patch, ts, nil
   107  }
   108  

View as plain text