Contents of p7s files - digital-signature

Does anyone out there know the content of the p7s file?
At least one digital signature is located in the file, and I can locate that pretty easily, but I want to catch the part of the file that contains the section encrypted with the private key - i.e., the non-repudiation part of the digital signature.
Does anyone know where a simple copy of the general file format can be found?
SUPPLEMENT ON EDIT:
The general format of the files I am working with is:
byte offset Record Type
0 x509 cert (or so the program says)
0 version
1 8x (information type)
3 1 offset to next information (length of file - 4)
52 x509 cert (embedded, collection member: ROOT CA)
56 x509 cert (embedded, collection member: ROOT CA)
(1 offset) x509 cert (new, subject identifier: Email)
(1 offset +4) x509 cert (embedded, collection memeber: Email )
(varies) x509 cert (new, enhanced key usage: Digital Signature, Non-Repudiation)
(varies+4) x509 cert (embedded, collection member: Digital Signature, Non-Repudiation))
(varies) x509 cert (new, certificate authority info: CA EMAIL)
(varies+4) x509 cert (embedded, collection member: CA EMAIL)
(varies) crosscertificate pair information, unknown class type
(varies) certificate of unknown class type (padded with trailing zeros, if needed)
I do know that this file does not contain a message digest, and is not unique except it is original to the certificate holder (i.e., a different certificate will product different results, but different messages all have the same p7s file attached to them).
I believe the message digest is stripped from the files when they are sent to a system that does not support encryption/decryption of emails (such as gmail or yahoo). That would be my explanation for the lack of distinct contents for the p7s files.
The files are not damaged other than the likelihood that the message digest has been stripped from them. They will not open with ASN. Regular certificate files will open with ASN (cer files).
I wrote a program that analyzes the files by brute force, essentially.
I check the file byte by byte, and copy the bytes into the input for an X509Certificate2 class instantiation in a try-catch loop.
Whether it aborts or not, I move one byte and check again.
If the check is successful, I add the resulting cert to a collection.
At the end, I examine the certs in the collection and dump both hex and formatted ascii with the file offset into a report file.
The p7s files I am referring to are detached from the original file, and apparently do not contain any signed information. That is apparently stripped when the signature is sent to an email address that does not have the capability of encrypting/decrypting information.

P7S file usually contains DER encoded CMS (Cryptographic Message Syntax) structure of SignedData type which is defined in RFC5652. You can use ASN.1 Editor to conveniently examine exact structure and contents of your file.

I recently needed to get the contents of some files ".rtf.p7s". Looking at their content, using the notepad++, I could see that the RTF was there without cryptography after a fixed number of bytes. So I made this little script that removes the first bytes containing the key information that I did not need.
Ps - Open the file in sublime did not help. It opened the file as binary.
<?php
$dir = __dir__;
$dh = opendir($dir);
while (false !== ($filename = readdir($dh))) {
if( strpos( $filename, ".p7s" ) !== false ) {
$files[] = $filename;
}
}
foreach($files as $file ){
$content = file_get_contents( $file );
$newcontent = substr( $content, 62 );
$newfilename = substr( $file , 0, -4 );
file_put_contents($newfilename, $newcontent);
}
?>

Related

What determines the appended string when we sign a msix application with signtool

I bought a code signing certificate last year and signed a msix package using the sign tool
sign /f "$SigningKeyFilePath" /fd SHA256 /v /a /p $SigningKeyPassword "$Package"
The resultant msix package when installed created a folder in AppData directory with the name PackageName_244zpcd23egta, since the certificate was valid only for a year, we had to get a new certificate, we were told that we can't renew the existing.
Now after signing with the new certificate the folder created is different PackageName_123zwerd23ewea, this means that we can't update the previously installed application. MSIX installer returns error say a previous application with same name is already installed.
I want to know how can we prevent this problem in future? What determines the _randowm_looking_number at the end of folder? I have noticed the new certificate did not had the pin code. Could that make this happen? or that we should always insist on certificate renewal (if it is possible) and not get a new certificate?
The block appended at the end of the string is a publisher hash, calculated from your subject (publisher). It is a 13-character string, base32-encoded representation of first few bytes of SHA-256 hash of your certificate Distinguished Name.
The algorithm is relatively straightforward:
Take UTF-16 string containing the publisher name (certificate DN) (as-is, with all spaces and punctuations)
Calculate SHA-256 hash of byte representation of this string
Take first 8 bytes (64 bits)
Pad the binary value by a single zero bit to the right (= left shift all bits)
Group the bits in groups of 5 (since we had 64 + 1 bits, we should get 13 groups each having 5 bytes)
For each group, convert the bit representation to an integer, and perform a look-up in a replacement table mapping the numbers to letters and digits.
Join the letters together and make them lowercase to receive the publisher hash.
This can be done for example via the following PowerShell
function Get-PublisherHash($publisherName)
{
$publisherNameAsUnicode = [System.Text.Encoding]::Unicode.GetBytes($publisherName);
$publisherSha256 = [System.Security.Cryptography.HashAlgorithm]::Create("SHA256").ComputeHash($publisherNameAsUnicode);
$publisherSha256First8Bytes = $publisherSha256 | Select-Object -First 8;
$publisherSha256AsBinary = $publisherSha256First8Bytes | ForEach-Object { [System.Convert]::ToString($_, 2).PadLeft(8, '0') };
$asBinaryStringWithPadding = [System.String]::Concat($publisherSha256AsBinary).PadRight(65, '0');
$encodingTable = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
$result = "";
for ($i = 0; $i -lt $asBinaryStringWithPadding.Length; $i += 5)
{
$asIndex = [System.Convert]::ToInt32($asBinaryStringWithPadding.Substring($i, 5), 2);
$result += $encodingTable[$asIndex];
}
return $result.ToLower();
}
For example:
Get-PublisherHash "CN=SomeName, DN=Some Domain"
> qwz5zh2hhehvm
Any change of your certificate (where the publisher name changes) means that the hash is completely different. And since the hash is a part of MSIX family name and its full package name, the new app is treated as another application.
In some recent efforts to change it (Insider Builds 22000 and newer) there is a feature called "Persistent identity", which can be used to provide a smooth upgrade experience even if the certificate changes.
Source:
My blog post about calculating the hash
Microsoft documentation for feature "Persistent identity"
Description of base32 algorithm

Verifyable logfile at customer site

We want to create a logfile at customer site where
the customer is able to read the log (plain text)
we can verify at our site that the log file isn't manipulated
A few hundred bytes of unreadable data is okay. But some customers do not send us files where they can't verify that they do not contain sensible data.
The only reasonable option I see so far is to append a cryptographic checksum (e.g. SHA256(SECRET_VALUE + "logtext")). The SECRET_VALUE would be something hardcoded which is plain "security through obscurity". Is there any better way?
We use the DotNet-library and I do not want to implement any crypto algorithm by hand if that matters.
You can use standard HMAC algorithm with a secret key to perform the checksum.
Using a secret key prevents in a simple way that the checksum can be regenerated directly. A hardcoded key could be extracted from code, but for your use case I think is enough
The result is a binary hash. To insert it into the text file encode the value as hexadecimal or base64, and ensure you are able to revert the process in server side so you can calculate the hash again with the original file.
You could use also a detached hash file to avoid modifying the log file
Target
customer readable logfiles
verifyable by our side
minimum of binary data
must work offline
Options
Public-Private-key-things... (RSA, ...)
would be secure
but only binary data
Add a signature
We are not the first ones with that idea ( https://en.wikipedia.org/wiki/Hash-based_message_authentication_code )
DotNet supports that ( System.Security.Cryptography.HMACSHA256 )
Key must be stored somewhere ... in source
Even with obfuscation: not possible to do so securely
Trusted Timestamping
again: we are not first ( https://en.wikipedia.org/wiki/Trusted_timestamping )
needs connection to "trusted third party" (means: a web service)
Build Hash + TimeStamp -> send to third party -> sign the data (public-private-key stuff) -> send back
Best option so far
Add a signature with HMAC
Store the key in native code (not THAT easy to extract)
Get code obfuscation running and build some extra loops in C#
Every once in a while (5min?) put a signature into log AND into windows application log
application log is at least basically secured against modification (read only)
and it's collected by the our error report
easy to oversee by customer (evil grin)

Convert *.pem certs into mozilla certdata.txt

There is numbers of tools that converts certdata.txt from here into .pem format again. However I would need to do it the opposing way: create certadata.txt from a given .pem or .der file.
Does anyone knows a tool that converts *.pem certs into the certdata.txt?
After getting a closer look of nss-tools I have found what I really needed:
nss-addbuiltin:
Read a der-encoded cert from certfile or stdin, and output
it to stdout in a format suitable for the builtin root module.
Example: nss-addbuiltin -n MyCA -t "C,C,C" -i myca.der >> certdata.txt
The file you referenced is a definition file. You generally never feed it directly to an application, instead you convert the certdata.txt into a list of certificates in .pem format.
This is what most of consumers fo:
https://groups.google.com/forum/#!topic/mozilla.dev.security.policy/J7mY_cpOyX4
http://curl.haxx.se/cvssource/lib/mk-ca-bundle.pl
https://security.stackexchange.com/questions/42946/where-can-i-find-all-ssl-ca-certificates
If you use the PEM list, then it's just as simple as adding your certificate to the end of that list.

How to compute the digest for the SignedProperties of a XAdES signature?

I've been struggling for several days about how to compute the digest for the SignedProperties element in a XAdES signature. I have a reference XML file with the two digest values computed (the file being signed and and the signed properties), and I know it's good because it passes the verifiers. I computed the right digest value for the file being signed, but whatever I give as an input to the digest method (I use OpenSSL), I cannot get the same value that in the reference file. Of course my own file don't pass the verifier after that. I use the following command to compute the digest:
openssl dgst -sha256 -binary myfile.xml | openssl base64
I recorded the file myfile.xml by extracting the SignedProperties element of the reference file and saved it as is.
<xades:SignedProperties Id="xmldsig-f6a6a2a1-87af-4720-8eed-cf4532e99106-signedprops"><xades:SignedSignatureProperties><xades:SigningTime>2015-09-22T09:02:48.624+02:00</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>cAJECbIzXZiLH+ILWPrM5jfA13GKcEC8t1qe7/BxqBM=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>CN=thawte SHA256 Code Signing CA,O=thawte\, Inc.,C=US</ds:X509IssuerName><ds:X509SerialNumber>13010307134774063901853305426952669967</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate></xades:SignedSignatureProperties><xades:SignedDataObjectProperties><xades:DataObjectFormat ObjectReference="#xmldsig-f6a6a2a1-87af-4720-8eed-cf4532e99106-ref0"><xades:Description>signature détachée du fichier indexfile.txt</xades:Description><xades:MimeType>text/plain</xades:MimeType></xades:DataObjectFormat></xades:SignedDataObjectProperties></xades:SignedProperties></xades:SignedProperties>
Apparently, I should get the value :
6JK3GHDL25+EIRefNMQJ3SOGSI8uzQ45PiziMomZkYs=
But I can't get it. I don't know if some transformations or canonicalization must be applied, the specification is very vague about this part. It's encoded in UTF-8, no line feeds.
Does anyone how to do this ? Any trick ?
I finally found out how to obtain the right digest value. Apparently, the same canonicalization algorithm must be applied to the SignedProperties element, although this is not described precisely in the recommendation. I missed two important things in generating the canonized form :
Auto-closed tags must be explicitly opened and closed : becomes
Any namespace declared in an ancestor element must be reported in the root element of the document subset, even if it is not used in this particular subset, which I found quite weird.
Anyway the correct canonized form for this subset is :
<xades:SignedProperties xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Id="SignedProperties"><xades:SignedSignatureProperties><xades:SigningTime>2015-09-22T09:02:48.624+02:00</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></ds:DigestMethod><ds:DigestValue>cAJECbIzXZiLH+ILWPrM5jfA13GKcEC8t1qe7/BxqBM=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>CN=thawte SHA256 Code Signing CA,O=thawte\, Inc.,C=US</ds:X509IssuerName><ds:X509SerialNumber>13010307134774063901853305426952669967</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate></xades:SignedSignatureProperties><xades:SignedDataObjectProperties><xades:DataObjectFormat ObjectReference="#SignedFile"><xades:Description>signature détachée du fichier indexfile.txt</xades:Description><xades:MimeType>text/plain</xades:MimeType></xades:DataObjectFormat></xades:SignedDataObjectProperties></xades:SignedProperties>

How can I import a .pfx file that was created without a password?

I have created a PFX PDU using the java bouncycastle library. Inside the PFX PDU, there are two certificates and two encrypted private keys. All the contents are used as PKCS#7 data content (i.e. no encryption, stored as octet strings).I organised the elements according to the guidelines of PKCS#12 (RFC 7292 Section 5). Then I wrote the DER encoded byte array to a file.
I opened the file in a hex editor and saw that the object structure is OK. I have also read the file contents and built a bouncycastle PFX object from it. But when I try to open the .pfx file from my file system, the Certificate Import Wizard asks for the password for the private key. I did not use any password to create the PFX object. I have tried to use empty string and the password used for encrypting the private keys, but they didn't work. It shows "The password you entered is incorrect.".
Is there something I missed here? How can I get the password required to import certificates?
In RFC 7292, section 4.1, page 41, details of AuthenticatedSafe is described. AutthenticatedSafe is sequence OF ContentInfo which could one of three types.
AuthenticatedSafe ::= SEQUENCE OF ContentInfo
-- Data if unencrypted
-- EncryptedData if password-encrypted
-- EnvelopedData if public key-encrypted
Make your authenticatedSafe data as EncryptedData where you needs to encrypt the BERencoded value of AuthenticatedSafe with the SecretKey generated from password you will give using SecretKeyFactory and PBEParameterSpec.
Hope that, this will help you. Cheers !!!

Resources