SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo encodes a GOST R 34.10-2012-256 key as GOST R 34.10-2001 when the key uses a legacy CryptoPro parameter set OID.
The following combination is valid:
- Key algorithm:
1.2.643.7.1.1.1.1 — GOST R 34.10-2012-256
- Public key parameter set:
1.2.643.2.2.36.0 — CryptoPro-XchA
- Digest:
1.2.643.7.1.1.2.2 — GOST R 34.11-2012-256
However, Bouncy Castle 2.7.0 serializes the resulting SubjectPublicKeyInfo with:
1.2.643.2.2.19 — GOST R 34.10-2001
instead of:
1.2.643.7.1.1.1.1 — GOST R 34.10-2012-256.
RFC 9215 section 4.2 allows GOST R 34.10-2001 parameter-set identifiers to be used as publicKeyParamSet values for GOST R 34.10-2012 keys.
The issue appears to be caused by SubjectPublicKeyInfoFactory selecting the key algorithm based only on whether PublicKeyParamSet is present in cryptoProOids.
To Reproduce
Create GOST parameters using CryptoPro-XchA as the public key parameter set and GOST R 34.11-2012-256 as the digest:
var curveOid =
CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA;
var domain =
ECGost3410NamedCurves.GetByOid(curveOid);
var namedDomain = new ECNamedDomainParameters(
curveOid,
domain);
var gostParameters = new ECGost3410Parameters(
namedDomain,
curveOid,
RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256,
null);
var generationParameters = new ECKeyGenerationParameters(
gostParameters,
new SecureRandom());
var generator = new ECKeyPairGenerator();
generator.Init(generationParameters);
var keyPair = generator.GenerateKeyPair();
var spki =
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
keyPair.Public);
Console.WriteLine(spki.Algorithm.Algorithm.Id);
Actual output:
The relevant code in SubjectPublicKeyInfoFactory is:
return new SubjectPublicKeyInfo(
new AlgorithmIdentifier(
!cryptoProOids.Contains(parameters7.PublicKeyParamSet)
? (elementEncodingLength > 32
? RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512
: RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256)
: CryptoProObjectIdentifiers.GostR3410x2001,
new Gost3410PublicKeyAlgParameters(
parameters7.PublicKeyParamSet,
parameters7.DigestParamSet,
parameters7.EncryptionParamSet)),
CreateECGost3410PublicKey(elementEncodingLength, q));
Since 1.2.643.2.2.36.0 is included in cryptoProOids, the key algorithm is always selected as GOST R 34.10-2001.
Expected Behavior
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo should be able to produce:
Algorithm:
1.2.643.7.1.1.1.1
Parameters:
publicKeyParamSet: 1.2.643.2.2.36.0
digestParamSet: 1.2.643.7.1.1.2.2
That is:
GOST R 34.10-2012-256
+ CryptoPro-XchA parameter set
+ GOST R 34.11-2012-256
There should either be a way to explicitly specify the GOST key algorithm independently of the parameter-set OID, or SubjectPublicKeyInfoFactory should not assume that every CryptoPro parameter-set OID implies GOST R 34.10-2001.
As a workaround, constructing the AlgorithmIdentifier explicitly produces the expected SubjectPublicKeyInfo:
var bcSpki =
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
keyPair.Public);
var algorithmIdentifier = new AlgorithmIdentifier(
RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256,
new Gost3410PublicKeyAlgParameters(
curveOid,
RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256));
var correctSpki = new SubjectPublicKeyInfo(
algorithmIdentifier,
bcSpki.ParsePublicKey());
Screenshots and Logs
BouncyCastle version: 2.7.0
Input ECGost3410Parameters:
PublicKeyParamSet : 1.2.643.2.2.36.0
DigestParamSet : 1.2.643.7.1.1.2.2
Field size : 256 bits
SubjectPublicKeyInfoFactory output:
Algorithm : 1.2.643.2.2.19
PublicKeyParamSet : 1.2.643.2.2.36.0
DigestParamSet : 1.2.643.7.1.1.2.2
Expected SubjectPublicKeyInfo:
Algorithm : 1.2.643.7.1.1.1.1
PublicKeyParamSet : 1.2.643.2.2.36.0
DigestParamSet : 1.2.643.7.1.1.2.2
Manually replacing only the AlgorithmIdentifier while keeping the public key encoding generated by Bouncy Castle produces the expected certificate.
Product Deployment
- Deployment format: NuGet package / .NET application
- Package:
BouncyCastle.Cryptography
- Version:
2.7.0
- Runtime:
.NET 10
Desktop
- OS: macOS
- Browser: N/A
- Version: N/A
Additional Context
RFC 9215 section 4.2 allows GOST R 34.10-2001 parameter-set identifiers to be used with GOST R 34.10-2012 public keys.
The specific combination required here is:
key algorithm = 1.2.643.7.1.1.1.1
publicKeyParamSet = 1.2.643.2.2.36.0
digestParamSet = 1.2.643.7.1.1.2.2
This combination is also accepted by CryptoPro CSP.
The current implementation seems unable to represent it through ECGost3410Parameters and SubjectPublicKeyInfoFactory, because the presence of a CryptoPro parameter-set OID forces the algorithm OID to GOST R 34.10-2001.
Is there an intended API in Bouncy Castle 2.7.0 for explicitly selecting GOST R 34.10-2012 while retaining a legacy CryptoPro parameter-set OID?
If not, cryptoProOids.Contains(PublicKeyParamSet) does not appear to be sufficient to distinguish GOST R 34.10-2001 keys from GOST R 34.10-2012 keys.
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfoencodes a GOST R 34.10-2012-256 key as GOST R 34.10-2001 when the key uses a legacy CryptoPro parameter set OID.The following combination is valid:
1.2.643.7.1.1.1.1— GOST R 34.10-2012-2561.2.643.2.2.36.0— CryptoPro-XchA1.2.643.7.1.1.2.2— GOST R 34.11-2012-256However, Bouncy Castle 2.7.0 serializes the resulting
SubjectPublicKeyInfowith:1.2.643.2.2.19— GOST R 34.10-2001instead of:
1.2.643.7.1.1.1.1— GOST R 34.10-2012-256.RFC 9215 section 4.2 allows GOST R 34.10-2001 parameter-set identifiers to be used as
publicKeyParamSetvalues for GOST R 34.10-2012 keys.The issue appears to be caused by
SubjectPublicKeyInfoFactoryselecting the key algorithm based only on whetherPublicKeyParamSetis present incryptoProOids.To Reproduce
Create GOST parameters using CryptoPro-XchA as the public key parameter set and GOST R 34.11-2012-256 as the digest:
Actual output:
The relevant code in
SubjectPublicKeyInfoFactoryis:Since
1.2.643.2.2.36.0is included incryptoProOids, the key algorithm is always selected as GOST R 34.10-2001.Expected Behavior
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfoshould be able to produce:That is:
There should either be a way to explicitly specify the GOST key algorithm independently of the parameter-set OID, or
SubjectPublicKeyInfoFactoryshould not assume that every CryptoPro parameter-set OID implies GOST R 34.10-2001.As a workaround, constructing the
AlgorithmIdentifierexplicitly produces the expectedSubjectPublicKeyInfo:Screenshots and Logs
Manually replacing only the
AlgorithmIdentifierwhile keeping the public key encoding generated by Bouncy Castle produces the expected certificate.Product Deployment
BouncyCastle.Cryptography2.7.0.NET 10Desktop
Additional Context
RFC 9215 section 4.2 allows GOST R 34.10-2001 parameter-set identifiers to be used with GOST R 34.10-2012 public keys.
The specific combination required here is:
This combination is also accepted by CryptoPro CSP.
The current implementation seems unable to represent it through
ECGost3410ParametersandSubjectPublicKeyInfoFactory, because the presence of a CryptoPro parameter-set OID forces the algorithm OID to GOST R 34.10-2001.Is there an intended API in Bouncy Castle 2.7.0 for explicitly selecting GOST R 34.10-2012 while retaining a legacy CryptoPro parameter-set OID?
If not,
cryptoProOids.Contains(PublicKeyParamSet)does not appear to be sufficient to distinguish GOST R 34.10-2001 keys from GOST R 34.10-2012 keys.