private static void WriteGpgFormatSignature(X509Certificate2 certificate, bool isDetached) { const int signatureCode = 0; // GPGSM uses 0 as well. var signatureType = isDetached ? "D" : "S"; var(algorithmCode, hashCode) = CertificateHelper.ToPgpPublicKeyAlgorithmCode(certificate); GpgOutputHelper.WriteLine($"{SignatureCreated} {signatureType} {algorithmCode} {hashCode} {signatureCode} {DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)} {certificate.Thumbprint}"); }
/// <summary> /// Write out the format in the GPG format. /// </summary> /// <param name="goodSignature">If this is a good signature or not.</param> /// <param name="certificates">The certificates to write.</param> private static void WriteGpgCertificateData(bool goodSignature, X509Certificate2Collection certificates) { var type = goodSignature ? GoodSignature : BadSignature; foreach (var certificate in certificates) { GpgOutputHelper.WriteLine($"{type} {certificate.Thumbprint} {certificate.Subject}"); } }
/// <summary> /// Performs a signing operation. /// </summary> /// <param name="certificate">The certificate to use for signing.</param> /// <param name="bytes">The bytes to sign.</param> /// <param name="timeStampAuthority">A optional RFC3161 timestamp authority to sign against.</param> /// <param name="isDetached">If we should be producing detached results.</param> /// <param name="useArmor">If we should encode in PEM format.</param> /// <param name="includeOption">The certificate include options, if we should just include end certificates, or intermediate/root certificates as well.</param> /// <returns>0 if the operation was successful, 1 otherwise.</returns> internal static async Task <int> PerformSign(X509Certificate2 certificate, byte[] bytes, Uri timeStampAuthority, bool isDetached, bool useArmor, X509IncludeOption includeOption) { if (certificate == null) { throw new ArgumentNullException(nameof(certificate), Resources.InvalidCertificate); } if (!certificate.HasPrivateKey) { throw new ArgumentException($"The certificate {certificate.Thumbprint} has a invalid signing key.", nameof(certificate)); } if (bytes == null) { throw new ArgumentNullException(nameof(bytes), Resources.NothingToEncrypt); } // Git is looking for "\n[GNUPG:] SIG_CREATED ", meaning we need to print a // line before SIG_CREATED. BEGIN_SIGNING seems appropriate. GPG emits this, // though GPGSM does not. GpgOutputHelper.WriteLine(BeginSigning); var contentInfo = new ContentInfo(bytes); var cms = new SignedCms(contentInfo, isDetached); var signer = new CmsSigner(certificate) { IncludeOption = includeOption }; signer.SignedAttributes.Add(new Pkcs9SigningTime()); cms.ComputeSignature(signer, false); // If we are provided with a authority, add the timestamp certificate into our unsigned attributes. if (timeStampAuthority != null) { InfoOutputHelper.WriteLine("Stamping with RFC 3161 Time Stamp Authority: " + timeStampAuthority); await TimeStamper.GetAndSetRfc3161Timestamp(cms, timeStampAuthority).ConfigureAwait(false); } var encoding = cms.Encode(); // Write out the signature in GPG expected format. WriteGpgFormatSignature(certificate, isDetached); KeyOutputHelper.Write(encoding, useArmor); InfoOutputHelper.WriteLine("Finished signing"); GpgOutputHelper.Flush(); InfoOutputHelper.Flush(); return(0); }
public static int Do(string[] fileNames) { GpgOutputHelper.WriteLine(NewSig); if (fileNames.Length < 2) { VerifyAttached(fileNames.FirstOrDefault()); } else { VerifyDetached(fileNames); } return(0); }
/// <summary> /// Common code for both the attached/detached cases. It will verify that the signatures are valid for the data. /// </summary> /// <param name="signedCms">The signed CMS which we will validate.</param> /// <param name="body">The bytes we want to validate against.</param> /// <param name="verifySignatureOnly">If we should verify the signature only. Useful for testing only.</param> internal static void VerifySignedData(SignedCms signedCms, byte[] body, bool verifySignatureOnly = false) { try { signedCms.Decode(body); signedCms.CheckSignature(verifySignatureOnly); if (signedCms.SignerInfos.Count == 0) { throw new SignClientException(Resources.InvalidSigningInfo); } var issuedCertificate = signedCms.SignerInfos[0].Certificate; foreach (var signedInfo in signedCms.SignerInfos) { if (TimeStamper.CheckRFC3161Timestamp(signedInfo, issuedCertificate.NotBefore, issuedCertificate.NotAfter) == false) { throw new SignClientException(Resources.InvalidTimestamp); } } WriteGpgCertificateData(true, signedCms.Certificates); WriteSigningInformation(issuedCertificate, true, signedCms); GpgOutputHelper.WriteLine($"{FullyTrusted} 0 shell"); // This indicates we fully trust using the x509 model. } catch (Exception) { if (signedCms.Certificates.Count == 0) { GpgOutputHelper.WriteLine(ErrorSignature); } else { var issuedCertificate = signedCms.SignerInfos[0].Certificate; WriteGpgCertificateData(false, signedCms.Certificates); WriteSigningInformation(issuedCertificate, false, signedCms); } throw; } }