Skip to content
Open
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
14 changes: 7 additions & 7 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ default_language_version:
python: python3
repos:
- repo: https://github.com/psf/black
rev: 19.10b0
rev: 22.3.0
hooks:
- id: black
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v6.8.0
rev: v8.14.0
hooks:
- id: eslint
verbose: true
args:
- --color
- --fix
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
rev: v4.2.0
hooks:
- id: trailing-whitespace
# exclude autogenerated files
Expand All @@ -48,7 +48,7 @@ repos:
- id: mixed-line-ending
args: ["--fix=lf"]
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.9
rev: 3.9.2
hooks:
- id: flake8
name: flake8 except __init__.py
Expand All @@ -60,7 +60,7 @@ repos:
files: /__init__\.py$
additional_dependencies: ["flake8-bugbear==19.8.0"]
- repo: https://github.com/pre-commit/mirrors-pylint
rev: v2.5.3
rev: v3.0.0a4
hooks:
- id: pylint
name: pylint with optional checks
Expand All @@ -70,11 +70,11 @@ repos:
name: pylint with mandatory checks
args: ["--rcfile=.pylintrc-mandatory"]
- repo: https://github.com/asottile/pyupgrade
rev: v1.26.2
rev: v2.32.0
hooks:
- id: pyupgrade
- repo: https://github.com/pre-commit/mirrors-isort
rev: v4.3.21
rev: v5.10.1
hooks:
- id: isort
name: isort except __init__.py
Expand Down
1 change: 1 addition & 0 deletions src/xmlsig/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .hmac import HMACAlgorithm
from .rsa import RSAAlgorithm
from .dsa import DSAAlgorithm
123 changes: 123 additions & 0 deletions src/xmlsig/algorithms/dsa.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# © 2017 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import struct
from base64 import b64decode, b64encode

from asn1crypto.algos import DSASignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.asymmetric import dsa

from xmlsig.algorithms.base import Algorithm
from xmlsig.ns import NS_MAP, DSigNs
from xmlsig.utils import USING_PYTHON2, b64_print, create_node, long_to_bytes


def i2osp(x, x_len):
if x >= pow(256, x_len):
raise ValueError("integer too large")
digits = []
while x:
digits.append(int(x % 256))
x //= 256
for _i in range(x_len - len(digits)):
digits.append(0)
return bytearray(digits[::-1])


def os2ip(arr):
x_len = len(arr)
x = 0
for i in range(x_len):
if USING_PYTHON2:
val = struct.unpack("B", arr[i])[0]
else:
val = arr[i]
x = x + (val * pow(256, x_len - i - 1))
return x


def to_int(element):
if USING_PYTHON2:
return struct.unpack("B", element)[0]
return element


class DSAAlgorithm(Algorithm):
private_key_class = dsa.DSAPrivateKey
public_key_class = dsa.DSAPublicKey

@staticmethod
def sign(data, private_key, digest):
return DSASignature.load(private_key.sign(data, digest())).to_p1363()

@staticmethod
def verify(signature_value, data, public_key, digest):
public_key.verify(
DSASignature.from_p1363(b64decode(signature_value)).dump(), data, digest()
)

@staticmethod
def key_value(node, public_key):
result = create_node("DSAKeyValue", node, DSigNs, "\n", "\n")
public_numbers = public_key.public_numbers()
if public_numbers.parameter_numbers.p is not None:
create_node(
"P",
result,
DSigNs,
tail="\n",
text="\n"
+ b64_print(
b64encode(long_to_bytes(public_numbers.parameter_numbers.p))
)
+ "\n",
)
if public_numbers.parameter_numbers.q is not None:
create_node(
"Q",
result,
DSigNs,
tail="\n",
text="\n"
+ b64_print(
b64encode(long_to_bytes(public_numbers.parameter_numbers.q))
)
+ "\n",
)
if public_numbers.parameter_numbers.g is not None:
create_node(
"G",
result,
DSigNs,
tail="\n",
text="\n"
+ b64_print(
b64encode(long_to_bytes(public_numbers.parameter_numbers.g))
)
+ "\n",
)
if public_numbers.y is not None:
create_node(
"Y",
result,
DSigNs,
tail="\n",
text="\n"
+ b64_print(b64encode(long_to_bytes(public_numbers.y)))
+ "\n",
)
return result

@staticmethod
def get_public_key(key_info, context):
key = key_info.find("ds:KeyInfo/ds:KeyValue/ds:DSAKeyValue", namespaces=NS_MAP)
if key is not None:
p = os2ip(b64decode(key.find("ds:P", namespaces=NS_MAP).text))
q = os2ip(b64decode(key.find("ds:Q", namespaces=NS_MAP).text))
g = os2ip(b64decode(key.find("ds:G", namespaces=NS_MAP).text))
y = os2ip(b64decode(key.find("ds:Y", namespaces=NS_MAP).text))
return dsa.DSAPublicNumbers(y, dsa.DSAParameterNumbers(p, q, g)).public_key(
default_backend()
)
return super(DSAAlgorithm, DSAAlgorithm).get_public_key(key_info, context)
9 changes: 7 additions & 2 deletions src/xmlsig/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

from cryptography.hazmat.primitives import hashes

from .algorithms import HMACAlgorithm, RSAAlgorithm
from .algorithms import DSAAlgorithm, HMACAlgorithm, RSAAlgorithm
from .ns import NS_MAP # noqa:F401
from .ns import DSignNsMore, DSigNs, DSigNs11, EncNs
from .ns import DSignNsMore, DSigNs, DSigNs2, DSigNs11, EncNs

ID_ATTR = "Id"

Expand All @@ -18,6 +18,7 @@
TransformEnveloped = DSigNs + "enveloped-signature"
TransformXPath = "http://www.w3.org/TR/1999/REC-xpath-19991116"
TransformXPath2 = ""
TransformXPathFilter2 = "http://www.w3.org/2002/06/xmldsig-filter2"
TransformXPointer = ""
TransformXslt = "http://www.w3.org/TR/1999/REC-xslt-19991116"
TransformRemoveXmlTagsC14N = ""
Expand Down Expand Up @@ -61,6 +62,8 @@
TransformSha384 = DSignNsMore + "sha384"
TransformSha512 = EncNs + "sha512"

TransformXmlSig2Tranform = DSigNs2 + "transform"

TransformUsageUnknown = {}
TransformUsageDSigTransform = [TransformEnveloped, TransformBase64]
TransformUsageC14NMethod = {
Expand Down Expand Up @@ -102,6 +105,8 @@
TransformHmacSha256: {"digest": hashes.SHA256, "method": HMACAlgorithm},
TransformHmacSha384: {"digest": hashes.SHA384, "method": HMACAlgorithm},
TransformHmacSha512: {"digest": hashes.SHA512, "method": HMACAlgorithm},
TransformDsaSha1: {"digest": hashes.SHA1, "method": DSAAlgorithm},
TransformDsaSha256: {"digest": hashes.SHA256, "method": DSAAlgorithm},
}

TransformUsageEncryptionMethod = {}
Expand Down
1 change: 1 addition & 0 deletions src/xmlsig/ns.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

DSigNs = "http://www.w3.org/2000/09/xmldsig#"
DSigNs11 = "http://www.w3.org/2009/xmldsig11#"
DSigNs2 = "http://www.w3.org/2010/xmldsig2#"
DSignNsMore = "http://www.w3.org/2001/04/xmldsig-more#"
EncNs = "http://www.w3.org/2001/04/xmlenc#"
XPathNs = "http://www.w3.org/TR/1999/REC-xpath-19991116"
Expand Down
Loading