diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2018-09-14 17:54:02 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2018-09-14 17:54:02 +0700 |
commit | 297ccc3cc304defd9ecb0ba944bede4f89696b3b (patch) | |
tree | cd76cba6a46d74fa58a4b07af0221040840a3ce7 /crypto/src | |
parent | RFC 8032: Implement Ed25519ctx, Ed25519ph, Ed448ph variants (diff) | |
download | BouncyCastle.NET-ed25519-297ccc3cc304defd9ecb0ba944bede4f89696b3b.tar.xz |
RFC 5958: Update PrivateKeyInfo
- now supports optional 'publicKey' field
Diffstat (limited to 'crypto/src')
-rw-r--r-- | crypto/src/asn1/pkcs/PrivateKeyInfo.cs | 193 | ||||
-rw-r--r-- | crypto/src/util/collections/CollectionUtilities.cs | 8 |
2 files changed, 139 insertions, 62 deletions
diff --git a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs index c5be7a315..dfb332fdd 100644 --- a/crypto/src/asn1/pkcs/PrivateKeyInfo.cs +++ b/crypto/src/asn1/pkcs/PrivateKeyInfo.cs @@ -4,15 +4,55 @@ using System.IO; using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Math; +using Org.BouncyCastle.Utilities.Collections; namespace Org.BouncyCastle.Asn1.Pkcs { + /** + * RFC 5958 + * + * <pre> + * [IMPLICIT TAGS] + * + * OneAsymmetricKey ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] Attributes OPTIONAL, + * ..., + * [[2: publicKey [1] PublicKey OPTIONAL ]], + * ... + * } + * + * PrivateKeyInfo ::= OneAsymmetricKey + * + * Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) + * + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * { PUBLIC-KEY, + * { PrivateKeyAlgorithms } } + * + * PrivateKey ::= OCTET STRING + * -- Content varies based on type of key. The + * -- algorithm identifier dictates the format of + * -- the key. + * + * PublicKey ::= BIT STRING + * -- Content varies based on type of key. The + * -- algorithm identifier dictates the format of + * -- the key. + * + * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } + * </pre> + */ public class PrivateKeyInfo : Asn1Encodable { - private readonly Asn1OctetString privKey; - private readonly AlgorithmIdentifier algID; - private readonly Asn1Set attributes; + private readonly DerInteger version; + private readonly AlgorithmIdentifier privateKeyAlgorithm; + private readonly Asn1OctetString privateKey; + private readonly Asn1Set attributes; + private readonly DerBitString publicKey; public static PrivateKeyInfo GetInstance(Asn1TaggedObject obj, bool explicitly) { @@ -25,110 +65,139 @@ namespace Org.BouncyCastle.Asn1.Pkcs if (obj == null) return null; if (obj is PrivateKeyInfo) - return (PrivateKeyInfo) obj; + return (PrivateKeyInfo)obj; return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj)); } - public PrivateKeyInfo(AlgorithmIdentifier algID, Asn1Encodable privateKey) - : this(algID, privateKey, null) + private static int GetVersionValue(DerInteger version) + { + BigInteger bigValue = version.Value; + if (bigValue.CompareTo(BigInteger.Zero) < 0 || bigValue.CompareTo(BigInteger.One) > 0) + throw new ArgumentException("invalid version for private key info", "version"); + + return bigValue.IntValue; + } + + public PrivateKeyInfo( + AlgorithmIdentifier privateKeyAlgorithm, + Asn1Encodable privateKey) + : this(privateKeyAlgorithm, privateKey, null, null) { } public PrivateKeyInfo( - AlgorithmIdentifier algID, - Asn1Encodable privateKey, - Asn1Set attributes) + AlgorithmIdentifier privateKeyAlgorithm, + Asn1Encodable privateKey, + Asn1Set attributes) + : this(privateKeyAlgorithm, privateKey, attributes, null) { - this.algID = algID; - this.privKey = new DerOctetString(privateKey.GetEncoded(Asn1Encodable.Der)); + } + + public PrivateKeyInfo( + AlgorithmIdentifier privateKeyAlgorithm, + Asn1Encodable privateKey, + Asn1Set attributes, + byte[] publicKey) + { + this.version = new DerInteger(publicKey != null ? BigInteger.One : BigInteger.Zero); + this.privateKeyAlgorithm = privateKeyAlgorithm; + this.privateKey = new DerOctetString(privateKey); this.attributes = attributes; + this.publicKey = publicKey == null ? null : new DerBitString(publicKey); } private PrivateKeyInfo(Asn1Sequence seq) { IEnumerator e = seq.GetEnumerator(); - e.MoveNext(); - BigInteger version = ((DerInteger)e.Current).Value; - if (version.IntValue != 0) - { - throw new ArgumentException("wrong version for private key info: " + version.IntValue); - } + this.version = DerInteger.GetInstance(CollectionUtilities.RequireNext(e)); - e.MoveNext(); - algID = AlgorithmIdentifier.GetInstance(e.Current); - e.MoveNext(); - privKey = Asn1OctetString.GetInstance(e.Current); + int versionValue = GetVersionValue(version); - if (e.MoveNext()) + this.privateKeyAlgorithm = AlgorithmIdentifier.GetInstance(CollectionUtilities.RequireNext(e)); + this.privateKey = Asn1OctetString.GetInstance(CollectionUtilities.RequireNext(e)); + + int lastTag = -1; + while (e.MoveNext()) { - attributes = Asn1Set.GetInstance((Asn1TaggedObject)e.Current, false); + Asn1TaggedObject tagged = (Asn1TaggedObject)e.Current; + + int tag = tagged.TagNo; + if (tag <= lastTag) + throw new ArgumentException("invalid optional field in private key info", "seq"); + + lastTag = tag; + + switch (tag) + { + case 0: + { + this.attributes = Asn1Set.GetInstance(tagged, false); + break; + } + case 1: + { + if (versionValue < 1) + throw new ArgumentException("'publicKey' requires version v2(1) or later", "seq"); + + this.publicKey = DerBitString.GetInstance(tagged, false); + break; + } + default: + { + throw new ArgumentException("unknown optional field in private key info", "seq"); + } + } } } - public virtual AlgorithmIdentifier PrivateKeyAlgorithm + public virtual Asn1Set Attributes { - get { return algID; } + get { return attributes; } } - [Obsolete("Use 'PrivateKeyAlgorithm' property instead")] - public virtual AlgorithmIdentifier AlgorithmID + /// <summary>Return true if a public key is present, false otherwise.</summary> + public virtual bool HasPublicKey { - get { return algID; } + get { return publicKey != null; } + } + + public virtual AlgorithmIdentifier PrivateKeyAlgorithm + { + get { return privateKeyAlgorithm; } } public virtual Asn1Object ParsePrivateKey() { - return Asn1Object.FromByteArray(privKey.GetOctets()); + return Asn1Object.FromByteArray(privateKey.GetOctets()); } - [Obsolete("Use 'ParsePrivateKey' instead")] - public virtual Asn1Object PrivateKey + /// <summary>For when the public key is an ASN.1 encoding.</summary> + public virtual Asn1Object ParsePublicKey() { - get - { - try - { - return ParsePrivateKey(); - } - catch (IOException) - { - throw new InvalidOperationException("unable to parse private key"); - } - } + return publicKey == null ? null : Asn1Object.FromByteArray(publicKey.GetOctets()); } - public virtual Asn1Set Attributes + /// <summary>Return the public key as a raw bit string.</summary> + public virtual DerBitString PublicKeyData { - get { return attributes; } + get { return publicKey; } } - /** - * write out an RSA private key with its associated information - * as described in Pkcs8. - * <pre> - * PrivateKeyInfo ::= Sequence { - * version Version, - * privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}}, - * privateKey PrivateKey, - * attributes [0] IMPLICIT Attributes OPTIONAL - * } - * Version ::= Integer {v1(0)} (v1,...) - * - * PrivateKey ::= OCTET STRING - * - * Attributes ::= Set OF Attr - * </pre> - */ public override Asn1Object ToAsn1Object() { - Asn1EncodableVector v = new Asn1EncodableVector(new DerInteger(0), algID, privKey); + Asn1EncodableVector v = new Asn1EncodableVector(version, privateKeyAlgorithm, privateKey); if (attributes != null) { v.Add(new DerTaggedObject(false, 0, attributes)); } + if (publicKey != null) + { + v.Add(new DerTaggedObject(false, 1, publicKey)); + } + return new DerSequence(v); } } diff --git a/crypto/src/util/collections/CollectionUtilities.cs b/crypto/src/util/collections/CollectionUtilities.cs index 18fcb6774..cac158226 100644 --- a/crypto/src/util/collections/CollectionUtilities.cs +++ b/crypto/src/util/collections/CollectionUtilities.cs @@ -39,6 +39,14 @@ namespace Org.BouncyCastle.Utilities.Collections return new UnmodifiableSetProxy(s); } + public static object RequireNext(IEnumerator e) + { + if (!e.MoveNext()) + throw new InvalidOperationException(); + + return e.Current; + } + public static string ToString(IEnumerable c) { StringBuilder sb = new StringBuilder("["); |