2013-10-10 13 views
3

C# 코드의 CryptoAPI를 사용하여 SHA256 타임 스탬프를 서명 된 어셈블리에 추가하려고합니다.CryptoAPI의 SignerTimeStampEx2 (PInvoke 사용)

Signer.TimestampSignedAssembly("MyAssembly.exe", "http://tsa.starfieldtech.com"); 

서명자 클래스 :

public static class Signer 
{ 
    [StructLayoutAttribute(LayoutKind.Sequential)] 
    struct SIGNER_SUBJECT_INFO 
    { 
     public uint cbSize; 
     public IntPtr pdwIndex; 
     public uint dwSubjectChoice; 
     public SubjectChoiceUnion Union1; 
     [StructLayoutAttribute(LayoutKind.Explicit)] 
     internal struct SubjectChoiceUnion 
     { 
      [FieldOffsetAttribute(0)] 
      public IntPtr pSignerFileInfo; 
      [FieldOffsetAttribute(0)] 
      public IntPtr pSignerBlobInfo; 
     } 
    } 

    [StructLayoutAttribute(LayoutKind.Sequential)] 
    struct SIGNER_FILE_INFO 
    { 
     public uint cbSize; 
     public IntPtr pwszFileName; 
     public IntPtr hFile; 
    } 

    [DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
    private static extern int SignerTimeStampEx2(
     uint dwFlags,    // DWORD 
     IntPtr pSubjectInfo,  // SIGNER_SUBJECT_INFO 
     string pwszHttpTimeStamp, // LPCWSTR 
     uint dwAlgId,    // ALG_ID 
     IntPtr psRequest,   // PCRYPT_ATTRIBUTES 
     IntPtr pSipData,   // LPVOID 
     out IntPtr ppSignerContext // SIGNER_CONTEXT 
     ); 

    public static void TimestampSignedAssembly(string appPath, string tsaServer) 
    { 
     if (tsaServer == null) throw new ArgumentNullException("tsaServer"); 

     var pSubjectInfo = IntPtr.Zero;    
     try 
     {     
      pSubjectInfo = CreateSignerSubjectInfo(appPath); 
      TimestampSignedAssembly(pSubjectInfo, tsaServer); 
     } 
     finally 
     {     
      if (pSubjectInfo != IntPtr.Zero) 
      { 
       Marshal.DestroyStructure(pSubjectInfo, typeof(SIGNER_SUBJECT_INFO)); 
      }     
     } 
    } 

    private static IntPtr CreateSignerSubjectInfo(string pathToAssembly) 
    { 
     var info = new SIGNER_SUBJECT_INFO 
     { 
      cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)), 
      pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint))) 
     }; 
     var index = 0; 
     Marshal.StructureToPtr(index, info.pdwIndex, false); 

     info.dwSubjectChoice = 0x1; //SIGNER_SUBJECT_FILE 
     var assemblyFilePtr = Marshal.StringToHGlobalUni(pathToAssembly); 

     var fileInfo = new SIGNER_FILE_INFO 
     { 
      cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_FILE_INFO)), 
      pwszFileName = assemblyFilePtr, 
      hFile = IntPtr.Zero 
     }; 

     info.Union1 = new SIGNER_SUBJECT_INFO.SubjectChoiceUnion 
     { 
      pSignerFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_FILE_INFO))) 
     }; 

     Marshal.StructureToPtr(fileInfo, info.Union1.pSignerFileInfo, false); 

     IntPtr pSubjectInfo = Marshal.AllocHGlobal(Marshal.SizeOf(info)); 
     Marshal.StructureToPtr(info, pSubjectInfo, false); 

     return pSubjectInfo; 
    } 

    /* 
     Here CryptoAPI function SignerTimeStampEx2 called. 
    */ 
    private static void TimestampSignedAssembly(IntPtr pSubjectInfo, string tsaServer) 
    {    
     IntPtr context; 
     var hResult = SignerTimeStampEx2(
      0x1,   // I have not found anywhere what value should have this parameter! 
      pSubjectInfo, 
      tsaServer,  
      0x0000800c,  // 256 bit SHA hashing algorithm. This value taken form here: http://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx 
      IntPtr.Zero,  
      IntPtr.Zero, 
      out context 
      ); 

     if (hResult != 0) 
     { 
      throw new Exception(string.Format("Error occured when adding timestamp - Error code: 0x{0:X}", hResult)); 
     } 
    } 
} 

내가 SignerTimeStampEx2에 전달 (dwAlgId)를 인수 기능을한다는 사실에도 불구하고이 SHA256 타임 스탬프를 추가 할 필요가 있음을 나타냅니다 여기에 내가 사용하고 코드입니다 (0x0000800c), SHA1 타임 스탬프가 항상 생성됩니다.

누구에게이 문제가 발생 했습니까? 내가 뭘 잘못하고있어? 에 대해 어떤 값을 설정해야합니까? dwFlagsdwAlgId 매개 변수는 무엇입니까?

미리 감사드립니다.

+1

+1. 첫 번째 플래그로 SIGNER_TIMESTAMP_RFC3161을 사용해야한다고 생각합니다. 이제 ... SIGNER_TIMESTAMP_RFC3161 및 SIGNER_TIMESTAMP_AUTHENTICODE 값을 찾을 수있는 위치를 모르겠습니다 ... mssign32.dll을 디스 어셈블 할 때 '1'은 SIGNER_TIMESTAMP_AUTHENTICODE를 의미한다고 생각합니다 (SignerTimeStamp는 첫 번째 매개 변수 값으로 1을 사용하여 SignerTimeStampEx3을 호출하기 때문에). 따라서 플래그 값으로 0, 2 또는 3을 시도해야합니다. –

+0

답변 주셔서 감사합니다. 0, 2, 3을 플래그 값으로 전달하려고 시도하고 다음 결과가 나타납니다. 0과 3 - 0x80070057 오류 발생 (하나 이상의 인수가 유효하지 않음), 2 - APPCRASH in crypt32.dll (오류 코드 - c0000005, 액세스 위반 ?) – ruslangil

+0

진행 상황 :-) SIGNER_FILE_INFO에서 pwszFileName을 수정할 수도 있습니다. 문자열을 사용하고 CharSet = CharSet.Unicode를 구조체 정의에 추가하면됩니다. –

답변

6

dwFlags는 SIGNER_TIMESTAMP_RFC3161 (2)이어야합니다. 액세스 위반이 발생하는 이유는 SignerTimeStampEx2()가 documented입니다. 알고리즘은 DWORD 대신 PCSTR로 간주합니다. 0x800C를 전달하면 포인터로 참조를 취소하여 AV에 연결하려고합니다. 따라서 함수 선언에서 ALG_ID dwAlgId를 PCSTR pszTimeStampAlgorithmOid로 대체하십시오. "2.16.840.1.101.3.4.2.1"로 정의해야하는 szOID_NIST_sha256을 전달하십시오.

SignerTimeStampEx3()도 올바르지 않게 입니다. pszTimeStampAlgorithmOid는 PCWSTR이 아닌 PCSTR로 선언되어야합니다.

SIGNER_FILE_INFO 구조에서 파일 이름과 열린 Win32 파일 핸들을 모두 지정하면 코드 서명과 타임 스탬프가 더 안정적입니다.

SHA-256 타임 스탬프를 실제로받을 지 여부는 사용중인 타임 스탬프 서비스에 따라 다릅니다. http://tsa.starfieldtech.com, http://timestamp.globalsign.com/http://timestamp.comodoca.com/rfc3161은 SHA-256 타임 스탬프를 발행합니다. 다른 서비스는 SHA-256 타임 스탬프를 요구할 때조차도 SHA-1 타임 스탬프를 발행 할 수 있습니다.

+0

방금 ​​비슷한 문제가 발생하여 실제로 SignerTimeStampEx2 *를 사용하여 파일에 서명 할 수 있지만 SignerTimeStampEx2에 대한 API 문서는 잘못되었으므로 ALG_ID를 매개 변수로 사용하는 대신 타임 스탬프 알고리즘을 사용하여 PCSTR을 사용합니다 oid, 언급 한대로 sha256의 경우 "2.16.840 ...."입니다. – Imron

+0

문제는 파일이 아니라 블롭에 서명하고 싶습니다. 항상 실패합니다 ... 어떤 GUID를 전달해야합니까? – Michael

0

마침내 작동했습니다. 여기에 Timestamper 클래스의 전체 코드는 다음과 같습니다

public static class Timestamper 
{ 
    [StructLayout(LayoutKind.Sequential)] 
    struct SIGNER_SUBJECT_INFO 
    { 
     public uint cbSize; 
     public IntPtr pdwIndex; 
     public uint dwSubjectChoice; 
     public SubjectChoiceUnion Union1; 
     [StructLayoutAttribute(LayoutKind.Explicit)] 
     internal struct SubjectChoiceUnion 
     { 
      [FieldOffsetAttribute(0)] 
      public IntPtr pSignerFileInfo; 
      [FieldOffsetAttribute(0)] 
      public IntPtr pSignerBlobInfo; 
     } 
    } 

    [StructLayoutAttribute(LayoutKind.Sequential)] 
    struct SIGNER_FILE_INFO 
    { 
     public uint cbSize; 
     public IntPtr pwszFileName; 
     public IntPtr hFile; 
    } 

    [DllImport("Mssign32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 
    private static extern int SignerTimeStampEx2(
     uint dwFlags,     // DWORD 
     IntPtr pSubjectInfo,    // SIGNER_SUBJECT_INFO 
     string pwszHttpTimeStamp,  // LPCWSTR 
     IntPtr pszTimeStampAlgorithmOid, // PCSTR 
     IntPtr psRequest,    // PCRYPT_ATTRIBUTES 
     IntPtr pSipData,     // LPVOID 
     out IntPtr ppSignerContext  // SIGNER_CONTEXT 
    ); 

    public static void TimestampSignedAssembly(string appPath, string tsaServer) 
    { 
     if (tsaServer == null) throw new ArgumentNullException("tsaServer"); 

     IntPtr pSubjectInfo = IntPtr.Zero; 
     try 
     { 
      pSubjectInfo = CreateSignerSubjectInfo(appPath); 
      TimestampSignedAssembly(pSubjectInfo, tsaServer); 
     } 
     finally 
     { 
      if (pSubjectInfo != IntPtr.Zero) 
      { 
       Marshal.DestroyStructure(pSubjectInfo, typeof(SIGNER_SUBJECT_INFO)); 
      } 
     } 
    } 

    private static IntPtr CreateSignerSubjectInfo(string pathToAssembly) 
    { 
     SIGNER_SUBJECT_INFO info = new SIGNER_SUBJECT_INFO 
     { 
      cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_SUBJECT_INFO)), 
      pdwIndex = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint))) 
     }; 

     int index = 0; 
     Marshal.StructureToPtr(index, info.pdwIndex, false); 

     info.dwSubjectChoice = 0x1; //SIGNER_SUBJECT_FILE 
     IntPtr assemblyFilePtr = Marshal.StringToHGlobalUni(pathToAssembly); 

     SIGNER_FILE_INFO fileInfo = new SIGNER_FILE_INFO 
     { 
      cbSize = (uint)Marshal.SizeOf(typeof(SIGNER_FILE_INFO)), 
      pwszFileName = assemblyFilePtr, 
      hFile = IntPtr.Zero 
     }; 

     info.Union1 = new SIGNER_SUBJECT_INFO.SubjectChoiceUnion 
     { 
      pSignerFileInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SIGNER_FILE_INFO))) 
     }; 

     Marshal.StructureToPtr(fileInfo, info.Union1.pSignerFileInfo, false); 

     IntPtr pSubjectInfo = Marshal.AllocHGlobal(Marshal.SizeOf(info)); 
     Marshal.StructureToPtr(info, pSubjectInfo, false); 

     return pSubjectInfo; 
    } 

    /* 
     Here CryptoAPI function SignerTimeStampEx2 called. 
    */ 
    private static void TimestampSignedAssembly(IntPtr pSubjectInfo, string tsaServer) 
    { 
     IntPtr context; 
     int hResult = SignerTimeStampEx2(
      0x2, // SIGNER_TIMESTAMP_RFC3161 
      pSubjectInfo, 
      tsaServer, 
      Marshal.StringToHGlobalAnsi("2.16.840.1.101.3.4.2.1"), // szOID_NIST_sha256 constant, SHA256 hashing algorithm. 
      IntPtr.Zero, 
      IntPtr.Zero, 
      out context 
     ); 

     if (hResult != 0) 
     { 
      throw new Exception(string.Format("Error occured when adding timestamp - Error code: 0x{0:X}", hResult)); 
     } 
    } 
} 

사용 예 :

Timestamper.TimestampSignedAssembly("Assembly.exe", "http://timestamp.comodoca.com/?td=sha256");