본문으로 건너뛰기
AZ Tools

PKCS#7 / CMS 인스펙터

.p7b, .p7s, .p7m을 브라우저에서 열어 콘텐츠 유형, 인증서, CRL, 서명자, 알고리즘, 서명 시각을 확인합니다. 업로드는 없습니다.

사용법

  1. 파일을 상자에 놓거나 붙여넣으세요. DER, 여러 라벨의 PEM, 껍데기 없는 순수 base64를 모두 받아들이며 어떤 형식으로 읽었는지 표시합니다.
  2. 먼저 콘텐츠 유형을 보세요. 서명자가 있는 signedData는 서명이고, 인증서만 있고 서명자가 없으면 번들이며, envelopedData와 encryptedData는 암호문 그대로입니다.
  3. 서명이라면 eContent를 확인하세요. 없으면 분리 서명이므로 서명 대상 원본 파일을 함께 보관해야 나중에 검증할 수 있습니다.
  4. 인증서를 체인 순서대로 훑어보세요. 끊긴 지점은 빠진 발급자 이름과 함께 표시되고, 어느 체인에도 속하지 않는 인증서는 따로 나열됩니다.
  5. 결론을 내리기 전에 맨 아래 설명을 읽으세요. 구조가 무엇을 뜻하는지, 그리고 여기서는 아무것도 검증하거나 복호화하지 않는다는 점을 알려 줍니다.

자세한 설명

펼치기

.p7b, .p7c, .p7s, .p7m이 담고 있는 PKCS#7 / CMS 껍데기를 브라우저 안에서만 읽어 그 안에 무엇이 들어 있는지 알려 줍니다. 콘텐츠 유형 OID가 나머지 전부를 결정하므로 이름과 숫자를 함께 보여 주고, 모르는 OID는 추측하지 않고 숫자 그대로 남깁니다. signedData에서 가장 중요한 사실은 대개 eContent의 유무입니다. 없으면 분리 서명이고, 그래서 메일에 딸려 온 .p7s 하나만으로는 원본 바이트 없이 아무것도 확인할 수 없습니다. 인증서만 있고 서명자와 콘텐츠가 없는 구조는 서명이 아니라 인증서 번들(.p7b)이라고 분명히 말해 줍니다. 인증서는 주체, 발급자, 일련번호, 유효기간, 키, 대체 이름, SHA-256 지문으로 요약하고 발급자와 주체를 맞춰 체인 순서로 정렬하므로 빠진 중간 인증서나 관계없는 인증서가 바로 드러납니다. 서명자마다 식별 방식(발급자와 일련번호 또는 버전 3의 주체 키 식별자), 다이제스트와 서명 알고리즘, 서명 시각, messageDigest, 그리고 지목한 인증서가 파일에 실제로 들어 있는지를 보여 줍니다. 서명된 속성이 있으면 서명은 콘텐츠가 아니라 그 속성 집합의 DER에 대해 계산되며, 손으로 검증하려는 사람 대부분이 여기서 막힙니다. UTCTime의 두 자리 연도는 1950~2049 구간으로 읽으므로 51은 2051이 아니라 1951입니다. 자바나 서명 장비가 흔히 내보내는 BER 부정 길이도 그대로 받아들입니다. 다만 검증은 하지 않습니다. 서명 확인도, 신뢰 저장소를 이용한 경로 검증도, 복호화도 하지 않습니다.

자주 묻는 질문

PKCS#7과 CMS는 무엇이 다른가요?

CMS(RFC 5652)는 RSA의 PKCS#7 v1.5를 IETF가 이어받은 규격이고, 실무에서 만나는 형태에서는 사실상 같은 바이트입니다. ContentInfo 안에 콘텐츠 유형 OID와 본문이 들어갑니다. CMS는 authEnvelopedData 같은 콘텐츠 유형을 추가했고, 서명자를 발급자와 일련번호 대신 주체 키 식별자로 지목할 수 있게 했으며 속성 규칙을 엄격히 했습니다. 확장자는 이 구분을 따르지 않아서 .p7b, .p7s, .p7m이 둘 중 어느 쪽이든 될 수 있고, 이 도구는 양쪽을 모두 읽어 어떤 콘텐츠 유형인지 알려 줍니다.

.p7s를 열었는데 문서가 없습니다. 파일이 깨진 건가요?

대개는 정상이며 분리 서명입니다. 분리 서명에서는 encapContentInfo에 eContentType만 있고 eContent가 없어서 파일에는 서명값과 인증서만 담깁니다. 서명 대상은 메일 본문이나 .p7s 옆에 놓인 파일처럼 따로 전달됩니다. S/MIME과 대부분의 서명 장비에서 정상적인 방식입니다. 대신 줄바꿈 하나까지 동일한 원본 바이트가 없으면 그 서명은 영영 검증할 수 없습니다.

.p7b는 무엇이고 왜 서명이 없나요?

.p7b는 실질적인 내용물이 인증서 집합뿐인 signedData입니다. eContent도 서명자도 없고 CRL조차 없는 경우가 많습니다. 윈도우와 자바가 체인을 배포할 컨테이너로 PKCS#7을 골랐기 때문에 생긴 형식이고, PEM을 이어 붙인 형태가 아닌 "체인"을 요청했을 때 CA가 주는 파일이 보통 이것입니다. 안에 서명된 것이 없으므로 버전이나 다이제스트 알고리즘 집합, 비어 있는 signerInfos는 인증서 목록을 감싼 빈 봉투일 뿐입니다.

서명된 속성은 무엇이고 왜 서명 대상이 달라지나요?

signedAttrs가 있으면 서명은 콘텐츠가 아니라 그 SET OF Attribute의 DER 인코딩에 대해 계산됩니다. 콘텐츠는 간접적으로만 묶입니다. 필수 속성인 messageDigest가 콘텐츠의 다이제스트를 담고 contentType이 유형을 담기 때문입니다. 그래서 직접 검증하려면 콘텐츠를 해시해 messageDigest와 비교한 뒤, 속성 집합을 파일에 저장된 [0]이 아니라 SET 태그(0x31)로 다시 인코딩해 그 위에서 서명을 확인해야 합니다. 이 태그 치환을 빠뜨리는 것이 손수 만든 검증이 실패하는 전형적인 이유입니다.

envelopedData를 복호화하거나 서명을 검증할 수 있나요?

못 합니다. 브라우저라서가 아닙니다. envelopedData는 콘텐츠 키를 수신자별 공개 키로 각각 암호화해 담으므로 열려면 수신자의 개인 키가 필요한데, 그 키는 파일에 없고 웹 페이지에 붙여넣어서도 안 됩니다. 서명은 자신이 덮는 정확한 바이트가 있어야 검증할 수 있고 분리 서명 파일에는 그 바이트가 없으며, 의미 있는 판정에는 체인을 검증할 신뢰 저장소도 필요합니다. 여기서 얻는 것은 구조의 완전한 해석이고, 다른 곳에서 검증이 왜 실패했는지는 대개 그 해석이 알려 줍니다.

부정 길이를 쓴다고 나옵니다. 문제인가요?

아닙니다. CMS 규격은 DER을 요구하지만 실제로는 BER을 내보내는 구현이 많습니다. 부정 길이는 길이 바이트가 0x80이고 내용 뒤에 두 바이트 종료 표시가 오는 형태이며, 스트리밍된 OCTET STRING은 조각으로 나뉜 구성형 문자열로 도착합니다. 자바의 CMS 라이브러리와 openssl의 스트리밍 모드가 모두 이렇게 만들기 때문에 이 도구는 그대로 받아들이고 조각을 다시 이어 붙입니다. 한 가지만 유의하면 됩니다. 서명은 특정 인코딩 바이트 위에서 계산되므로 BER 파일을 DER로 다시 인코딩한 뒤 검증하는 도구는 해시 대상 자체를 바꿔 버립니다.

관련 도구