github.com/saferwall/pe@v1.5.2/security_test.go (about)

     1  // Copyright 2018 Saferwall. All rights reserved.
     2  // Use of this source code is governed by Apache v2 license
     3  // license that can be found in the LICENSE file.
     4  
     5  package pe
     6  
     7  import (
     8  	"crypto/x509"
     9  	"fmt"
    10  	"reflect"
    11  	"runtime"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  type TestSecurityEntry struct {
    17  	Header         WinCertificate
    18  	Info           CertInfo
    19  	Verified       bool
    20  	SignatureValid bool
    21  	err            error
    22  }
    23  
    24  func TestParseSecurityDirectory(t *testing.T) {
    25  
    26  	tests := []struct {
    27  		in  string
    28  		out TestSecurityEntry
    29  	}{
    30  		{
    31  			getAbsoluteFilePath("test/putty.exe"),
    32  			TestSecurityEntry{
    33  				Header: WinCertificate{
    34  					Length:          0x3D90,
    35  					Revision:        0x200,
    36  					CertificateType: 0x2,
    37  				},
    38  				Info: CertInfo{
    39  					Issuer:             "GB, Greater Manchester, Salford, COMODO RSA Code Signing CA",
    40  					Subject:            "GB, Cambridgeshire, Cambridge, Simon Tatham, Simon Tatham",
    41  					NotBefore:          time.Date(2018, time.November, 13, 00, 00, 0, 0, time.UTC),
    42  					NotAfter:           time.Date(2021, time.November, 8, 23, 59, 59, 0, time.UTC),
    43  					SerialNumber:       "7c1118cbbadc95da3752c46e47a27438",
    44  					PublicKeyAlgorithm: x509.RSA,
    45  					SignatureAlgorithm: x509.SHA256WithRSA,
    46  				},
    47  				Verified:       true,
    48  				SignatureValid: true,
    49  				err:            nil,
    50  			},
    51  		},
    52  		{
    53  			getAbsoluteFilePath("test/putty_modified.exe"),
    54  			TestSecurityEntry{
    55  				Header: WinCertificate{
    56  					Length:          0x3D90,
    57  					Revision:        0x200,
    58  					CertificateType: 0x2,
    59  				},
    60  				Info: CertInfo{
    61  					Issuer:             "GB, Greater Manchester, Salford, COMODO RSA Code Signing CA",
    62  					Subject:            "GB, Cambridgeshire, Cambridge, Simon Tatham, Simon Tatham",
    63  					NotBefore:          time.Date(2018, time.November, 13, 00, 00, 0, 0, time.UTC),
    64  					NotAfter:           time.Date(2021, time.November, 8, 23, 59, 59, 0, time.UTC),
    65  					SerialNumber:       "7c1118cbbadc95da3752c46e47a27438",
    66  					PublicKeyAlgorithm: x509.RSA,
    67  					SignatureAlgorithm: x509.SHA256WithRSA,
    68  				},
    69  				Verified:       true,
    70  				SignatureValid: false,
    71  				err:            nil,
    72  			},
    73  		},
    74  		{
    75  			getAbsoluteFilePath("test/579fd8a0385482fb4c789561a30b09f25671e86422f40ef5cca2036b28f99648"),
    76  			TestSecurityEntry{
    77  				Header: WinCertificate{
    78  					Length:          0x3488,
    79  					Revision:        0x200,
    80  					CertificateType: 0x2,
    81  				},
    82  				Info: CertInfo{
    83  					Issuer:             "US, VeriSign Class 3 Code Signing 2010 CA",
    84  					Subject:            "US, California, Mountain View, Symantec Corporation, Symantec Corporation",
    85  					NotBefore:          time.Date(2016, time.December, 16, 00, 00, 0, 0, time.UTC),
    86  					NotAfter:           time.Date(2017, time.December, 17, 23, 59, 59, 0, time.UTC),
    87  					SerialNumber:       "0ebfea68d677b3e26cab41c33f3e69de",
    88  					PublicKeyAlgorithm: x509.RSA,
    89  					SignatureAlgorithm: x509.SHA1WithRSA,
    90  				},
    91  				Verified:       false,
    92  				SignatureValid: false,
    93  				err:            nil,
    94  			},
    95  		},
    96  
    97  		{
    98  			getAbsoluteFilePath("test/00121dae38f26a33da2990987db58738c5a5966930126a42f606a3b40e014624"),
    99  			TestSecurityEntry{
   100  				err: ErrSecurityDataDirInvalid,
   101  			},
   102  		},
   103  	}
   104  
   105  	for _, tt := range tests {
   106  		t.Run(tt.in, func(t *testing.T) {
   107  			ops := Options{Fast: true}
   108  			file, err := New(tt.in, &ops)
   109  			if err != nil {
   110  				t.Fatalf("New(%s) failed, reason: %v", tt.in, err)
   111  			}
   112  
   113  			err = file.Parse()
   114  			if err != nil {
   115  				t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err)
   116  			}
   117  
   118  			var va, size uint32
   119  			if file.Is64 {
   120  				oh64 := file.NtHeader.OptionalHeader.(ImageOptionalHeader64)
   121  				dirEntry := oh64.DataDirectory[ImageDirectoryEntryCertificate]
   122  				va = dirEntry.VirtualAddress
   123  				size = dirEntry.Size
   124  			} else {
   125  				oh32 := file.NtHeader.OptionalHeader.(ImageOptionalHeader32)
   126  				dirEntry := oh32.DataDirectory[ImageDirectoryEntryCertificate]
   127  				va = dirEntry.VirtualAddress
   128  				size = dirEntry.Size
   129  			}
   130  
   131  			err = file.parseSecurityDirectory(va, size)
   132  			if err != tt.out.err {
   133  				t.Fatalf("parseSecurityDirectory(%s) failed, reason: %v", tt.in, err)
   134  			}
   135  
   136  			got := file.Certificates
   137  			if tt.out.err == nil {
   138  				if !reflect.DeepEqual(got.Header, tt.out.Header) {
   139  					t.Fatalf("certificate header assertion failed, got %v, want %v", got.Header, tt.out.Header)
   140  				}
   141  				if !reflect.DeepEqual(got.Info, tt.out.Info) {
   142  					t.Fatalf("certificate info assertion failed, got %v, want %v", got.Info, tt.out.Info)
   143  				}
   144  			}
   145  			if tt.out.SignatureValid != got.SignatureValid {
   146  				t.Fatalf("signature verification failed, got %v, want %v", got.SignatureValid, tt.out.SignatureValid)
   147  			}
   148  			if runtime.GOOS == "linux" {
   149  				if tt.out.Verified != got.Verified {
   150  					t.Fatalf("certificate verification failed, got %v, want %v", got.Verified, tt.out.Verified)
   151  				}
   152  			}
   153  		})
   154  	}
   155  }
   156  
   157  func TestAuthentihash(t *testing.T) {
   158  
   159  	tests := []struct {
   160  		in  string
   161  		out string
   162  	}{
   163  		{getAbsoluteFilePath("test/putty.exe"),
   164  			"8be7d65593b0fff2e8b29004640261b8a0d4fcc651a14cd0b8b702b7928f8ee0"},
   165  		{getAbsoluteFilePath("test/mscorlib.dll"),
   166  			"a52bd7784efbf206dbda2db058f3928deaf15f6fedf2773affae56023e2f0edb"},
   167  		{getAbsoluteFilePath("test/liblzo2-2.dll"),
   168  			"ae603480b92c7ea3feca164010d2594f9a5282f8b732ecaa0aca29f3225835f6"},
   169  		{getAbsoluteFilePath("test/kernel32.dll"),
   170  			"595e4eb556587a1363ff297df9f354a377963ecac0bed19230992b9601426aae"},
   171  		{getAbsoluteFilePath("test/mfc40u.dll"),
   172  			"5c8acdf9b2c7854c6b8e22e973d2fbae9c68fc22513d24c68c8e8010b1663e67"},
   173  		{getAbsoluteFilePath("test/000057fd78f66e64e15f5070364c824a8923b6216bd8bcf6368857fb9674c483"),
   174  			""},
   175  	}
   176  
   177  	for _, tt := range tests {
   178  		t.Run(tt.in, func(t *testing.T) {
   179  			file, err := New(tt.in, &Options{})
   180  			if err != nil {
   181  				t.Fatalf("New(%s) failed, reason: %v", tt.in, err)
   182  			}
   183  			err = file.Parse()
   184  			if err != nil {
   185  				t.Fatalf("Parse(%s) failed, reason: %v", tt.in, err)
   186  			}
   187  
   188  			hash := file.Authentihash()
   189  			got := fmt.Sprintf("%x", hash)
   190  			if string(got) != tt.out {
   191  				t.Errorf("Authentihash(%s) got %v, want %v", tt.in, got, tt.out)
   192  			}
   193  		})
   194  	}
   195  }