Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potentially fix CMS Data Envelope creation for ECC certificates #1003

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions MimeKit/Cryptography/BouncyCastleSecureMimeContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1225,11 +1225,11 @@ public override Stream Verify (Stream signedData, out DigitalSignatureCollection
}
}

class CmsRecipientInfoGenerator : RecipientInfoGenerator
class OaepAwareRecipientInfoGenerator : RecipientInfoGenerator
{
readonly CmsRecipient recipient;

public CmsRecipientInfoGenerator (CmsRecipient recipient)
public OaepAwareRecipientInfoGenerator (CmsRecipient recipient)
{
this.recipient = recipient;
}
Expand Down Expand Up @@ -1268,6 +1268,9 @@ public RecipientInfo Generate (KeyParameter contentEncryptionKey, SecureRandom r
var publicKeyInfo = certificate.SubjectPublicKeyInfo;
AlgorithmIdentifier keyEncryptionAlgorithm;

// If the recipient explicitly opts in to OAEP encryption (even if
// the underlying certificate is not tagged with an OAEP OID),
// choose OAEP instead.
if (publicKey is RsaKeyParameters && recipient.RsaEncryptionPadding?.Scheme == RsaEncryptionPaddingScheme.Oaep) {
cipherboy marked this conversation as resolved.
Show resolved Hide resolved
keyEncryptionAlgorithm = recipient.RsaEncryptionPadding.GetAlgorithmIdentifier ();
} else {
Expand Down Expand Up @@ -1300,7 +1303,45 @@ Stream Envelope (CmsRecipientCollection recipients, Stream content, Cancellation

foreach (var recipient in recipients) {
if (unique.Add (recipient.Certificate)) {
cms.AddRecipientInfoGenerator (new CmsRecipientInfoGenerator (recipient));
var cert = recipient.Certificate;
var pub = recipient.Certificate.GetPublicKey();
if (pub is RsaKeyParameters) {
// Bouncy Castle dispatches OAEP based off the certificate type.
// However, callers of MimeKit expect to use OAEP in S/MIME with
// certificates with PKCS#1v1.5 OIDs as these tend to be more broadly
// compatible across the ecosystem. Thus, buidl our own
// RecipientInfoGenerator and register that for this key.
cms.AddRecipientInfoGenerator (new OaepAwareRecipientInfoGenerator (recipient));
} else if (pub is ECKeyParameters) {
var ecPub = (ECKeyParameters) pub;
var kg = GeneratorUtilities.GetKeyPairGenerator ("ECDH");
kg.Init(new ECKeyGenerationParameters (ecPub.Parameters, RandomNumberGenerator));
var kp = kg.GenerateKeyPair ();

// TODO: better handle algorithm selection.
if (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) {
var subjectKeyIdentifier = recipient.Certificate.GetExtensionValue (X509Extensions.SubjectKeyIdentifier);
cms.AddKeyAgreementRecipient (
CmsEnvelopedDataGenerator.ECDHSha1Kdf,
kp.Public,
kp.Private,
subjectKeyIdentifier.GetOctets (),
pub,
CmsEnvelopedGenerator.Aes128Wrap
);
} else {
cms.AddKeyAgreementRecipient (
CmsEnvelopedDataGenerator.ECDHSha1Kdf,
kp.Public,
kp.Private,
cert,
CmsEnvelopedGenerator.Aes128Wrap
);
}
} else {
var oid = cert.SubjectPublicKeyInfo.Algorithm.Algorithm.ToString();
throw new ArgumentException("Unknown type of recipient certificate: " + pub.GetType().Name + " (SubjectPublicKeyInfo OID = " + oid + ")");
}
count++;
}
}
Expand Down
4 changes: 2 additions & 2 deletions MimeKit/MimeKit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.3.0" />
</ItemGroup>

<ItemGroup>
Expand All @@ -99,4 +99,4 @@
<Compile Include="Utils\OptimizedOrdinalComparer.cs" Condition=" $(TargetFramework.StartsWith('net4')) Or '$(TargetFramework)' == 'netstandard2.0' " />
</ItemGroup>

</Project>
</Project>