...

Source file src/github.com/sassoftware/relic/lib/authenticode/pesign.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  	"bytes"
    21  	"context"
    22  	"crypto"
    23  	"debug/pe"
    24  	"encoding/asn1"
    25  	"encoding/binary"
    26  	"errors"
    27  
    28  	"github.com/sassoftware/relic/lib/binpatch"
    29  	"github.com/sassoftware/relic/lib/certloader"
    30  	"github.com/sassoftware/relic/lib/pkcs9"
    31  )
    32  
    33  // Sign the digest and return an Authenticode structure
    34  func (pd *PEDigest) Sign(ctx context.Context, cert *certloader.Certificate) (*binpatch.PatchSet, *pkcs9.TimestampedSignature, error) {
    35  	indirect, err := pd.GetIndirect()
    36  	if err != nil {
    37  		return nil, nil, err
    38  	}
    39  	ts, err := signIndirect(ctx, indirect, pd.Hash, cert)
    40  	if err != nil {
    41  		return nil, nil, err
    42  	}
    43  	patch, err := pd.MakePatch(ts.Raw)
    44  	if err != nil {
    45  		return nil, nil, err
    46  	}
    47  	return patch, ts, nil
    48  }
    49  
    50  func (pd *PEDigest) GetIndirect() (indirect SpcIndirectDataContentPe, err error) {
    51  	indirect, err = makePeIndirect(pd.Imprint, pd.Hash, OidSpcPeImageData)
    52  	if err != nil {
    53  		return
    54  	}
    55  	if len(pd.PageHashes) > 0 {
    56  		if err2 := pd.imprintPageHashes(&indirect); err2 != nil {
    57  			err = err2
    58  			return
    59  		}
    60  	}
    61  	return
    62  }
    63  
    64  func (pd *PEDigest) imprintPageHashes(indirect *SpcIndirectDataContentPe) error {
    65  	var attr SpcAttributePageHashes
    66  	switch pd.Hash {
    67  	case crypto.SHA1:
    68  		attr.Type = OidSpcPageHashV1
    69  	case crypto.SHA256:
    70  		attr.Type = OidSpcPageHashV2
    71  	default:
    72  		return errors.New("unsupported page hash type")
    73  	}
    74  	attr.Hashes = make([][]byte, 1)
    75  	attr.Hashes[0] = pd.PageHashes
    76  	blob, err := asn1.Marshal(attr)
    77  	if err != nil {
    78  		return err
    79  	}
    80  	serdata, err := asn1.Marshal(makeSet(blob))
    81  	if err != nil {
    82  		return err
    83  	}
    84  	indirect.Data.Value.File = SpcLink{}
    85  	indirect.Data.Value.File.Moniker.ClassID = SpcUUIDPageHashes
    86  	indirect.Data.Value.File.Moniker.SerializedData = serdata
    87  	return nil
    88  }
    89  
    90  // Create a patchset that will add or replace the signature from a previously
    91  // digested image with a new one
    92  func (pd *PEDigest) MakePatch(sig []byte) (*binpatch.PatchSet, error) {
    93  	// pack new cert table
    94  	padded := (len(sig) + 7) / 8 * 8
    95  	info := certInfo{
    96  		Length:          uint32(8 + padded),
    97  		Revision:        0x0200,
    98  		CertificateType: 0x0002,
    99  	}
   100  	var buf bytes.Buffer
   101  	binary.Write(&buf, binary.LittleEndian, info)
   102  	buf.Write(sig)
   103  	buf.Write(make([]byte, padded-len(sig)))
   104  	// pack data directory
   105  	certTbl := buf.Bytes()
   106  	var dd pe.DataDirectory
   107  	if pd.OrigSize >= (1 << 32) {
   108  		return nil, errors.New("PE file is too big")
   109  	}
   110  	dd.VirtualAddress = uint32(pd.OrigSize)
   111  	dd.Size = uint32(len(certTbl))
   112  	var buf2 bytes.Buffer
   113  	binary.Write(&buf2, binary.LittleEndian, dd)
   114  	// make patch
   115  	patch := binpatch.New()
   116  	patch.Add(pd.markers.posDDCert, 8, buf2.Bytes())
   117  	patch.Add(pd.OrigSize, int64(pd.markers.certSize), certTbl)
   118  	return patch, nil
   119  }
   120  
   121  type certInfo struct {
   122  	Length          uint32
   123  	Revision        uint16
   124  	CertificateType uint16
   125  }
   126  

View as plain text