Skip to content

Commit

Permalink
Ensure RSA OIDs have core.Null parameters across various structures
Browse files Browse the repository at this point in the history
  • Loading branch information
wbond committed Aug 30, 2016
1 parent 3aa0dca commit 381a4da
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 41 deletions.
91 changes: 56 additions & 35 deletions asn1crypto/algos.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,57 @@ class AlgorithmIdentifier(Sequence):
]


class _ForceNullParameters(object):
"""
Various structures based on AlgorithmIdentifier require that the parameters
field be core.Null() for certain OIDs. This mixin ensures that happens.
"""

# The following attribute, plus the parameters spec callback and custom
# __setitem__ are all to handle a situation where parameters should not be
# optional and must be Null for certain OIDs. More info at
# https://tools.ietf.org/html/rfc4055#page-15
_null_algos = set([
'1.2.840.113549.1.1.1', # rsassa_pkcs1v15 / rsaes_pkcs1v15 / rsa
'1.2.840.113549.1.1.11', # sha256_rsa
'1.2.840.113549.1.1.12', # sha384_rsa
'1.2.840.113549.1.1.13', # sha512_rsa
'1.2.840.113549.1.1.14', # sha224_rsa
])

def _parameters_spec(self):
if self._oid_pair == ('algorithm', 'parameters'):
algo = self['algorithm'].native
if algo in self._oid_specs:
return self._oid_specs[algo]

if self['algorithm'].dotted in self._null_algos:
return Null

return None

_spec_callbacks = {
'parameters': _parameters_spec
}

# We have to override this since the spec callback uses the value of
# algorithm to determine the parameter spec, however default values are
# assigned before setting a field, so a default value can't be based on
# another field value (unless it is a default also). Thus we have to
# manually check to see if the algorithm was set and parameters is unset,
# and then fix the value as appropriate.
def __setitem__(self, key, value):
res = super(_ForceNullParameters, self).__setitem__(key, value)
if key != 'algorithm':
return res
if self['algorithm'].dotted not in self._null_algos:
return res
if self['parameters'].__class__ != Void:
return res
self['parameters'] = Null()
return res


class HmacAlgorithmId(ObjectIdentifier):
_map = {
'1.3.14.3.2.10': 'des_mac',
Expand Down Expand Up @@ -212,47 +263,17 @@ class SignedDigestAlgorithmId(ObjectIdentifier):
}


class SignedDigestAlgorithm(Sequence):
class SignedDigestAlgorithm(_ForceNullParameters, Sequence):
_fields = [
('algorithm', SignedDigestAlgorithmId),
('parameters', Any, {'optional': True}),
]

# The following attribute, plus the parameters spec callback and custom
# __setitem__ are all to handle a situation where parameters should not be
# optional and must be Null for certain OIDs. More info at
# https://tools.ietf.org/html/rfc4055#page-15
_null_algos = set(['sha224_rsa', 'sha256_rsa', 'sha384_rsa', 'sha512_rsa'])

def _parameters_spec(self):
algo = self['algorithm'].native
if algo == 'rsassa_pss':
return RSASSAPSSParams
if algo in self._null_algos:
return Null
return None

_spec_callbacks = {
'parameters': _parameters_spec
_oid_pair = ('algorithm', 'parameters')
_oid_specs = {
'rsassa_pss': RSASSAPSSParams,
}

# We have to override this since the spec callback uses the value of
# algorithm to determine the parameter spec, however default values are
# assigned before setting a field, so a default value can't be based on
# another field value (unless it is a default also). Thus we have to
# manually check to see if the algorithm was set and parameters is unset,
# and then fix the value as appropriate.
def __setitem__(self, key, value):
res = super(SignedDigestAlgorithm, self).__setitem__(key, value)
if key != 'algorithm':
return res
if self['algorithm'].native not in self._null_algos:
return res
if self['parameters'].__class__ != Void:
return res
self['parameters'] = Null()
return res

@property
def signature_algo(self):
"""
Expand Down Expand Up @@ -535,7 +556,7 @@ class EncryptionAlgorithmId(ObjectIdentifier):
}


class EncryptionAlgorithm(Sequence):
class EncryptionAlgorithm(_ForceNullParameters, Sequence):
_fields = [
('algorithm', EncryptionAlgorithmId),
('parameters', Any, {'optional': True}),
Expand Down
3 changes: 2 additions & 1 deletion asn1crypto/cms.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
zlib = None

from .algos import (
_ForceNullParameters,
DigestAlgorithm,
EncryptionAlgorithm,
HmacAlgorithm,
Expand Down Expand Up @@ -645,7 +646,7 @@ class KeyEncryptionAlgorithmId(ObjectIdentifier):
}


class KeyEncryptionAlgorithm(Sequence):
class KeyEncryptionAlgorithm(_ForceNullParameters, Sequence):
_fields = [
('algorithm', KeyEncryptionAlgorithmId),
('parameters', Any, {'optional': True}),
Expand Down
8 changes: 3 additions & 5 deletions asn1crypto/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
)
from ._errors import unwrap
from ._types import type_name, str_cls, byte_cls
from .algos import DigestAlgorithm, EncryptionAlgorithm
from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm
from .core import (
Any,
Asn1Value,
Expand Down Expand Up @@ -470,7 +470,7 @@ class PrivateKeyAlgorithmId(ObjectIdentifier):
}


class PrivateKeyAlgorithm(Sequence):
class PrivateKeyAlgorithm(_ForceNullParameters, Sequence):
"""
Original Name: PrivateKeyAlgorithmIdentifier
Source: https://tools.ietf.org/html/rfc5208#page-3
Expand All @@ -483,7 +483,6 @@ class PrivateKeyAlgorithm(Sequence):

_oid_pair = ('algorithm', 'parameters')
_oid_specs = {
'rsa': Null,
'dsa': DSAParams,
'ec': ECDomainParameters,
}
Expand Down Expand Up @@ -940,7 +939,7 @@ class PublicKeyAlgorithmId(ObjectIdentifier):
}


class PublicKeyAlgorithm(Sequence):
class PublicKeyAlgorithm(_ForceNullParameters, Sequence):
"""
Original Name: AlgorithmIdentifier
Source: https://tools.ietf.org/html/rfc5280#page-18
Expand All @@ -953,7 +952,6 @@ class PublicKeyAlgorithm(Sequence):

_oid_pair = ('algorithm', 'parameters')
_oid_specs = {
'rsa': Null,
'dsa': DSAParams,
'ec': ECDomainParameters,
'dh': DomainParameters,
Expand Down

0 comments on commit 381a4da

Please sign in to comment.