sgcSign 5분 시작 가이드
문서에 서명하는 컴포넌트는 서명기와 키 공급자 두 개예요. 이 페이지에서는 Windows 인증서 저장소의 인증서로 PAdES 방식의 PDF에 서명하고, 만든 결과를 검증하는 방법까지 보여 드려요. XML에 서명하고 싶다면 아래에 링크된 더 긴 XAdES 안내가 있어요.
문서에 서명하는 컴포넌트는 서명기와 키 공급자 두 개예요. 이 페이지에서는 Windows 인증서 저장소의 인증서로 PAdES 방식의 PDF에 서명하고, 만든 결과를 검증하는 방법까지 보여 드려요. XML에 서명하고 싶다면 아래에 링크된 더 긴 XAdES 안내가 있어요.
서명기는 문서 형식을 알고, 키 공급자는 개인 키가 어디에 있는지 알아요. 둘은 속성 하나로 만나요.
TsgcPAdESSigner는 sgcSign_PAdES.pas에 선언되어 있고 SGC Sign 팔레트 페이지에 등록돼요. SignPDFFile은 입력 경로와 출력 경로를 받아요.
Windows 인증서 저장소에는 TsgcWindowsCertStoreProvider를, .pfx 파일에는 TsgcPFXKeyProvider를 쓰세요. 둘 다 같은 팔레트 페이지에 있어요.
KeyProvider이며, 타입은 컴포넌트 참조가 아니라 인터페이스 IsgcKeyProvider예요. 이 차이는 수명 관리에 중요하며, 아래 문제 섹션에서 이유를 설명해요.
Win32, Win64, Linux64, Intel과 Apple Silicon의 macOS, iOS, Android를 지원해요. Windows에서는 해싱과 서명이 Windows CNG API를 거치고, 다른 모든 플랫폼에서는 라이브러리 자체의 순수 Pascal 암호화를 거쳐서 배포할 OpenSSL이 없어요. Windows 인증서 저장소 공급자만 Windows 전용으로 남는 유일한 컴포넌트예요.
sgcSign에는 기능 등급이 없어서 이 표는 에디션이 아니라 컴파일러와 플랫폼에 관한 거예요.
| 항목 | 값 |
|---|---|
| IDE | Delphi 7부터 RAD Studio 13까지, 그리고 C++Builder. C++Builder에서는 lib 폴더를 라이브러리 경로가 아니라 System Include 경로에 추가해요. |
| Uses 절 | 데모는 sgcSign_Types, sgcSign_Interfaces, sgcSign_Classes, sgcSign_PAdES, sgcSign_KeyProvider_WinCertStore, sgcSign_KeyProvider_PEM, sgcSign_KeyProvider_PFX를 작성해요. 쓰지 않는 공급자는 빼세요. |
| 에디션 | 없어요. 제품 자체의 sgcVer.inc에는 SGC_EDT_* define이 전혀 없고, 등급으로 제어되는 기능도 없어요. 라이브러리 하나에 모든 컴포넌트가 모든 라이선스에 들어 있어요. 상용 등급은 사용자 수 기준이며 Single, Team, Site가 있고, 무료 Community Edition도 있어요. |
| 플랫폼, 소스에서 확인한 내용 | Win32, Win64, Linux64, OSX64, OSXARM64, iOS, Android. 암호화는 sgcSign_Crypto.pas라는 하나의 연결 유닛을 거치며, Windows에서는 CNG이고 나머지에서는 순수 Pascal이에요. HTTP는 Windows에서는 WinHTTP이고 다른 곳에서는 Delphi RTL 클라이언트예요. 런타임 패키지는 Delphi 10.3부터 Linux64와 Intel macOS를, 10.4부터 Android와 iOS를, 11부터 Apple Silicon macOS를 지원해요. sgcSign_KeyProvider_WinCertStore.pas가 Windows 전용인 유일한 유닛이에요. |
| 외부 의존성 | 없어요. Windows에서는 라이브러리가 Windows CNG와 WinHTTP API를 직접 호출하고, 다른 플랫폼에서는 자체 순수 Pascal 암호화와 Delphi RTL HTTP 클라이언트를 쓰므로 애플리케이션과 함께 배포할 OpenSSL DLL이 없어요. |
| 기본값 | 새로 만든 TsgcPAdESSigner에는 이미 쓸 수 있는 프로필이 있어요. 생성자가 기본 PAdES 프로필, baseline B 서명 수준, SHA-256을 설정해요. 유효한 서명을 만들기 위해 Profile을 건드릴 필요가 없어요. |
PDF보다 XML이 필요한가요? 5분 XAdES 안내는 PFX 파일로 XML 문서에 서명하며, Delphi 7 유니코드 함정과 UTC 서명 시간도 다뤄요. 이 페이지는 PDF와 인증서 저장소에 대한 짝이 되는 안내예요.
디자인 타임 패키지는 런타임 패키지를 참조하므로, 런타임 패키지를 먼저 컴파일한 뒤 설치하세요.
다운로드한 파일을 폴더에 압축 해제하세요. 아래에서는 이 폴더를 {$DIR}이라고 불러요.
Tools, Environment Options, Directories로 이동해요. 모든 RAD Studio 버전에 적용되는 {$DIR}\delphi\source를 추가하세요.
버전별 폴더도 추가하세요. 예를 들어 RAD Studio 13에서는 {$DIR}\delphi\libD13\$(Platform)이고, Delphi 7에서는 libD7까지 있어요. C++Builder에서는 이 경로들을 System Include 경로에 추가해요.
IDE 버전에 맞는 Packages\sgcSignD13.groupproj를, C++Builder라면 sgcSignC13.groupproj를 여세요. sgcSign 패키지를 먼저 컴파일하고 그다음 dclsgcSign 패키지를 설치해요.
서명기, 검증기, 타임스탬프와 OCSP 클라이언트, 키 공급자 열 개가 들어 있는 SGC Sign 페이지가 나타나요. Windows에서는 Authenticode 서명기와 검증기도 함께 있어요.
인증서를 고르고, 서명기를 만들고, 공급자를 지정한 다음 SignPDFFile을 호출해요. 첫 번째 탭은 Windows 인증서 저장소를, 두 번째 탭은 PFX 파일을 사용해요.
uses
SysUtils, Classes,
// sgcSign
sgcSign_Types, sgcSign_Interfaces, sgcSign_Classes,
sgcSign_PAdES, sgcSign_KeyProvider_WinCertStore;
procedure TFormMain.btnSignClick(Sender: TObject);
var
vSigner: TsgcPAdESSigner;
vKeyProvider: TsgcWindowsCertStoreProvider;
vProviderIntf: IsgcKeyProvider;
vOutputFile: string;
begin
vKeyProvider := TsgcWindowsCertStoreProvider.Create(nil);
vSigner := TsgcPAdESSigner.Create(nil);
try
vKeyProvider.SelectCertificateBySubject('My Company');
Log('Certificate found: ' + vKeyProvider.Certificate.Subject);
// Hold the interface in an explicit local: an inline "as" cast
// would leave a compiler-generated interface temporary alive in
// this stack frame until the routine returns, i.e. past
// vKeyProvider.Free, and releasing it would touch freed memory.
vProviderIntf := vKeyProvider as IsgcKeyProvider;
vSigner.KeyProvider := vProviderIntf;
vSigner.Reason := 'Demo signature';
vSigner.Location := 'Spain';
vSigner.SignerName := 'sgcSign Demo';
vOutputFile := ChangeFileExt(edInputFile.Text, '_signed.pdf');
vSigner.SignPDFFile(edInputFile.Text, vOutputFile);
Log('SUCCESS: PDF signed with PAdES profile');
Log('Output file: ' + vOutputFile);
finally
vSigner.Free;
vProviderIntf := nil;
vKeyProvider.Free;
end;
end;
여기에 없는 것에 주목하세요. Profile은 전혀 건드리지 않아요. 생성자가 이미 기본 PAdES 프로필, baseline B 서명 수준, SHA-256을 설정하기 때문이에요. 인터페이스 임시 객체에 관한 주석은 포함된 데모 자체의 것이며, finally 블록의 해제 순서가 그것이 중요한 이유예요.
uses
SysUtils, Classes,
// sgcSign
sgcSign_Types, sgcSign_Interfaces, sgcSign_Classes,
sgcSign_PAdES, sgcSign_KeyProvider_PFX;
var
vSigner: TsgcPAdESSigner;
vKeyProvider: TsgcPFXKeyProvider;
vProviderIntf: IsgcKeyProvider;
begin
vKeyProvider := TsgcPFXKeyProvider.Create(nil);
vSigner := TsgcPAdESSigner.Create(nil);
try
vKeyProvider.FileName := 'C:\certs\signer.pfx';
vKeyProvider.Password := GetPfxPassword;
vKeyProvider.LoadFromFile;
Log('Certificate loaded (PFX): ' + vKeyProvider.Certificate.Subject);
vProviderIntf := vKeyProvider as IsgcKeyProvider;
vSigner.KeyProvider := vProviderIntf;
vSigner.SignPDFFile('C:\docs\contract.pdf',
'C:\docs\contract_signed.pdf');
finally
vSigner.Free;
vProviderIntf := nil;
vKeyProvider.Free;
end;
end;
첫 번째 탭과의 유일한 차이는 어떤 공급자를 만들고 키를 어떻게 지정하느냐예요. KeyProvider :=부터는 모두 동일하며, PKCS#11 하드웨어와 클라우드 키 서비스를 포함한 열 개의 공급자 모두 마찬가지예요.
uses
SysUtils, Classes,
// sgcSign
sgcSign_Types, sgcSign_Interfaces, sgcSign_Verifier;
var
oVerifier: TsgcSignatureVerifier;
vVerifier: IsgcSignatureVerifier;
oStream: TFileStream;
begin
oVerifier := TsgcSignatureVerifier.Create(nil);
oStream := TFileStream.Create('C:\docs\contract_signed.pdf',
fmOpenRead or fmShareDenyWrite);
try
// VerifyPDF is reached through the interface the component implements
vVerifier := oVerifier as IsgcSignatureVerifier;
if vVerifier.VerifyPDF(oStream) = vsValid then
Writeln('valid')
else
Writeln(oVerifier.GetVerificationDetails);
finally
vVerifier := nil;
oStream.Free;
oVerifier.Free;
end;
end;
서명기와 같은 인터페이스 규칙이에요. 캐스트 결과를 이름 있는 로컬 변수에 할당하고, 컴포넌트를 해제하기 전에 비우세요. 불리언 값만으로는 증거가 부족할 때는 GetValidationReportXML이 ETSI 검증 보고서 형식의 보고서를 만들어 줘요.
처음 두 탭은 포함된 데모 Demos\Delphi\PAdES\frmMain.pas에서 가져온 것이며, 분기를 탭마다 하나의 경로로 줄였어요. 인터페이스를 이름 있는 로컬 변수에 담으라는 주석은 데모 자체의 것이고 유지할 가치가 있어요. 더 풍부한 형제 데모인 Demos\Delphi\PAdES_Providers는 하드웨어와 클라우드 공급자로 같은 일을 해요.
파일이 생겼다고 해서 서명이 유효한 것은 아니에요.
데모처럼 선택한 뒤 Certificate.Subject를 읽어 보세요. 의도한 인증서로 서명했는지, 처음 일치한 아무 인증서로 서명했는지가 여기서 갈려요. IsLoaded는 같은 질문에 불리언으로 답해요.
SignPDFFile은 지정한 출력 경로에 써요. 포함된 데모는 ChangeFileExt로 경로를 만들어서 서명된 파일이 원본 옆에 생기도록 해요.
검사할 결과값이 없으므로 호출을 try except에 넣고 예외 메시지를 읽으세요. 데모가 그렇게 하며, 실패를 알리는 유일한 채널이에요.
파일이 있다고 유효한 서명은 아니에요. TsgcSignatureVerifier.VerifyPDF는 vsValid와 비교할 TsgcVerificationStatus를 반환하고, GetVerificationDetails가 실패를 설명해요. PDF 리더에서 파일을 열면 사람에게도 같은 결과가 보여요.
첫 서명의 문제는 거의 다 여섯 가지 중 하나가 원인이에요.
데모가 자체 주석에서 경고하는 바로 그 문제예요. KeyProvider는 IsgcKeyProvider를 받기 때문에 인라인 as 캐스트는 컴파일러가 만든 인터페이스 참조를 루틴이 반환될 때까지 살려 두는데, 그 시점은 공급자 컴포넌트를 해제한 뒤예요. 인터페이스를 이름 있는 로컬 변수에 할당하고, 서명기, 인터페이스를 nil로, 공급자 순서로 해제하세요.
TsgcSignProfileConfig 객체예요. Profile := 'something'이 아니라 Profile.Profile과 Profile.SignatureLevel을 설정해요. 생성자가 이미 쓸 수 있는 기본값을 채우므로 첫 샘플에서는 전혀 건드릴 필요가 없어요.
SelectCertificateBySubject는 주체로, SelectCertificateByThumbprint는 지문으로 찾아요. 데모처럼 선택한 뒤 Certificate.Subject를 읽어서 실제로 어떤 인증서가 선택되었는지 확인하세요. EnumerateCertificates는 사용 가능한 목록을 보여 줘요.
컴파일할 수 없어요. 서명기와 모든 공급자는 인터페이스 uses 절에 조건 없이 Windows를 넣기 때문에, 빈 유닛이 아니라 컴파일 오류가 나요. sgcSign은 Windows 라이브러리예요.
기본 서명에는 신뢰 앵커도 폐기 데이터도 없어요. TSAClient로 타임스탬프를 추가하고, 인증서가 만료된 뒤에도 문서를 검증할 수 있어야 한다면 장기 프로필로 올리세요.
의도된 설계예요. 검사할 반환값이 없으므로 호출을 try except에 넣고 예외 메시지를 읽으세요. 포함된 데모가 그렇게 해요.
네 가지 방향이 있고, 모두 같은 라이브러리 안에 있어요.
XML용 XAdES와 XMLDSig, 분리형 CMS용 CAdES, ASiC 컨테이너, 그리고 ClickOnce, NuGet, VSIX 패키지용 전용 서명기가 있어요. Windows에는 Authenticode 서명기도 있어요.
키 공급자가 열 개 제공돼요. PFX, PEM, Windows 저장소, PKCS#11 하드웨어, Azure Trusted Signing, AWS KMS, Google Cloud KMS, Certum SimplySign, HashiCorp Vault, CSC 원격 서명 프로토콜이에요.
스페인의 VeriFactu부터 EU 인보이스 형식까지 스물한 개의 국가 및 업종 프로파일이 있으며, 각각 해당 제도가 요구하는 필드와 서명 수준을 갖추고 있어요.
sgcSign Server는 키를 보관하고 요청에 따라 서명하는 자체 호스팅 데몬이라서, 인증서가 신뢰하는 컴퓨터를 벗어나지 않아요.
데모 프로젝트는 다운로드 안의 Demos\Delphi 아래에 있어요. 이 페이지는 PAdES 데모를 바탕으로 만들었어요.
| 5분 XAdES 안내 자세한 빠른 시작이에요. 새 VCL 프로젝트, PFX 파일, 서명된 XML 엔벨로프를 다뤄요. | 열기 | |
| 키 공급자 개인 키가 있을 수 있는 열 곳과, 각각에 필요한 것. | 열기 | |
| 서명 프로파일 스물한 개의 국가 및 업종 프로파일과 각각의 요구 사항. | 열기 | |
| PDF 서명 튜토리얼 눈에 보이는 서명을 포함한 PAdES의 더 긴 안내. | 열기 | |
| sgcSign Server 키가 이동해서는 안 될 때 쓰는 자체 호스팅 서명 데몬. | 열기 | |
| 체험판 다운로드 정식 버전과 같은 설치 프로그램이며 기간 제한이 있고, 무료 Community Edition도 있어요. | 열기 |
함께 읽어 보세요. sgcSign 소개와 코드 서명 서버. 모든 제품에는 각자의 빠른 시작이 있으며, 시작하기 페이지에서 모아 볼 수 있어요.
sgcSign_PAdES.pas에 선언된 TsgcPAdESSigner와 키 공급자예요. Windows 인증서 저장소에는 sgcSign_KeyProvider_WinCertStore.pas의 TsgcWindowsCertStoreProvider이고, .pfx 파일에는 sgcSign_KeyProvider_PFX.pas의 TsgcPFXKeyProvider예요. 둘 다 SGC Sign 팔레트 페이지에 있어요. 공급자를 서명기의 KeyProvider 속성에 할당한 다음 SignPDFFile(aInputFile, aOutputFile)을 호출하세요.
KeyProvider가 컴포넌트가 아니라 인터페이스 IsgcKeyProvider 타입이기 때문이에요. 인라인 as 캐스트는 컴파일러가 만든 인터페이스 임시 객체를 만들어 루틴이 반환될 때까지 스택 프레임에 살려 두는데, 그 시점은 공급자 컴포넌트가 해제된 뒤라서 이미 사라진 메모리를 건드리게 돼요. 데모는 캐스트 결과를 이름 있는 로컬 변수에 할당하고, 서명기, 인터페이스를 nil로, 공급자 순서로 해제해요. 그 순서를 그대로 따르세요.
sgcVer.inc에는 SGC_EDT_* define이 전혀 없고, 등급으로 제어되는 컴포넌트나 형식도 없어요. 모든 라이선스에 모든 서명기, 모든 키 공급자, 모든 국가 프로파일이 들어 있어요. 상용 등급은 사용자 수 기준인 Single, Team, Site이며, 체험판과 함께 무료 Community Edition도 있어요.
Profile은 TsgcSignProfileConfig 객체이므로 문자열을 할당하지 말고 Profile.Profile과 Profile.SignatureLevel을 설정하세요. 장기 서명이 필요하면 LTV 프로필과 baseline LT 수준으로 올리고 TSAClient를 연결하세요.
TsgcSignatureVerifier를 사용하세요. VerifyPDF는 스트림을 받아 TsgcVerificationStatus를 반환하며, 이를 vsValid와 비교해요. GetVerificationDetails는 실패를 설명하고, 불리언이 아니라 증거가 필요할 때는 GetValidationReportXML이 ETSI 검증 보고서 형식의 보고서를 만들어 줘요.