CVE-2020-12607 (published 2020-06-02T21:15Z)

An issue was discovered in fastecdsa before 2.1.2. When using the NIST P-256 curve in the ECDSA implementation, the point at infinity is mishandled. This means that for an extreme value in k and s^-1, the signature verification fails even if the signature is correct. This behavior is not solely a usability problem. There are some threat models where an attacker can benefit by successfully guessing users for whom signature verification will fail.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:P/I:N/A:N)
CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-347
cwe_name: Improper Verification of Cryptographic Signature
description: The product does not verify, or incorrectly verifies, the cryptographic signature for data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://github.com/AntonKueltz/fastecdsa
commit_details: repo_url: https://github.com/AntonKueltz/fastecdsa
author: AntonKueltz
author_date: 2020-04-14 02:52:44-07:00
msg: Update CHANGELOG.md
repository: repo_url: https://github.com/AntonKueltz/fastecdsa
repo_name: AntonKueltz/fastecdsa
description: Python library for fast elliptic curve crypto
repo_language: Python
owner: AntonKueltz
file_changes: filename: CHANGELOG.md
change_type: ModificationType.MODIFY
diff: @@ -2,7 +2,7 @@
 
 ## [2.1.2]
 ### Fixed
-- Point at infinity handling in C extensions
+- Point at infinity handling in C extensions (issue #52)
 - DER signature decoding that assumed length was always encoded in one byte
 
 ## [2.1.1]
@@ -28,4 +28,4 @@
 - Various unused imports
 
 ### Fixed
-- Issue with benchmark script when C extensions weren't built in place (issue #44)
\ No newline at end of file
+- Issue with benchmark script when C extensions weren't built in place (issue #44)

programming_language: Markdown
repo_url: https://github.com/AntonKueltz/fastecdsa
commit_details: repo_url: https://github.com/AntonKueltz/fastecdsa
author: AntonKueltz
author_date: 2020-04-14 02:45:48-07:00
msg: Update docs to v2.1.2
repository: repo_url: https://github.com/AntonKueltz/fastecdsa
repo_name: AntonKueltz/fastecdsa
description: Python library for fast elliptic curve crypto
repo_language: Python
owner: AntonKueltz
file_changes: filename: conf.py
change_type: ModificationType.MODIFY
diff: @@ -64,7 +64,7 @@ author = 'Anton Kueltz'
 # The short X.Y version.
 version = '2.1'
 # The full version, including alpha/beta/rc tags.
-release = '2.1.1'
+release = '2.1.2'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.

programming_language: Python
repo_url: https://github.com/AntonKueltz/fastecdsa
commit_details: repo_url: https://github.com/AntonKueltz/fastecdsa
author: AntonKueltz
author_date: 2020-04-14 02:15:41-07:00
msg: Properly handle the point at infinity
repository: repo_url: https://github.com/AntonKueltz/fastecdsa
repo_name: AntonKueltz/fastecdsa
description: Python library for fast elliptic curve crypto
repo_language: Python
owner: AntonKueltz
file_changes: filename: curveMath.c
change_type: ModificationType.MODIFY
diff: @@ -15,7 +15,22 @@ int pointZZ_pEqual(const PointZZ_p * op1, const PointZZ_p * op2) {
 }
 
 
+int pointZZ_pIsIdentityElement(const PointZZ_p * op) {
+    return mpz_cmp_ui(op->x, 0) == 0 && mpz_cmp_ui(op->y, 0) == 0 ? 1 : 0;
+}
+
+
+void pointZZ_pSetToIdentityElement(PointZZ_p * op) {
+    mpz_set_ui(op->x, 0);
+    mpz_set_ui(op->y, 0);
+}
+
+
 void pointZZ_pDouble(PointZZ_p * rop, const PointZZ_p * op, const CurveZZ_p * curve) {
+    if(pointZZ_pIsIdentityElement(op)) {
+        return pointZZ_pSetToIdentityElement(rop);
+    }
+
     mpz_t numer, denom, lambda;
     mpz_inits(numer, denom, lambda, NULL);
 
@@ -45,6 +60,35 @@ void pointZZ_pDouble(PointZZ_p * rop, const PointZZ_p * op, const CurveZZ_p * cu
 
 
 void pointZZ_pAdd(PointZZ_p * rop, const PointZZ_p * op1, const PointZZ_p * op2, const CurveZZ_p * curve) {
+    // handle identity element cases
+    if(pointZZ_pIsIdentityElement(op1) && pointZZ_pIsIdentityElement(op2)) {
+        return pointZZ_pSetToIdentityElement(rop);
+    } else if(pointZZ_pIsIdentityElement(op1)) {
+        mpz_set(rop->x, op2->x);
+        mpz_set(rop->y, op2->y);
+        return;
+    } else if(pointZZ_pIsIdentityElement(op2)) {
+        mpz_set(rop->x, op1->x);
+        mpz_set(rop->y, op1->y);
+        return;
+    }
+
+    // use doubling algorithm if points are equal
+    if(pointZZ_pEqual(op1, op2)) {
+        pointZZ_pDouble(rop, op1, curve);
+        return;
+    }
+
+    // check if points sum to identity element
+    mpz_t negy;
+    mpz_init(negy);
+    mpz_sub(negy, curve->p, op2->y);
+    if(mpz_cmp(op1->x, op2->x) == 0 && mpz_cmp(op1->y, negy) == 0) {
+        mpz_clear(negy);
+        return pointZZ_pSetToIdentityElement(rop);
+    }
+
+
     mpz_t xdiff, ydiff, lambda;
     mpz_inits(xdiff, ydiff, lambda, NULL);
 
@@ -67,11 +111,16 @@ void pointZZ_pAdd(PointZZ_p * rop, const PointZZ_p * op1, const PointZZ_p * op2,
     mpz_sub(rop->y, rop->y, op1->y);
     mpz_mod(rop->y, rop->y, curve->p);
 
-    mpz_clears(xdiff, ydiff, lambda, NULL);
+    mpz_clears(negy, xdiff, ydiff, lambda, NULL);
 }
 
 
 void pointZZ_pMul(PointZZ_p * rop, const PointZZ_p * point, const mpz_t scalar, const CurveZZ_p * curve) {
+    // handle the identity element
+    if(pointZZ_pIsIdentityElement(point)) {
+        return pointZZ_pSetToIdentityElement(rop);
+    }
+
     PointZZ_p R0, R1, tmp;
     mpz_inits(R1.x, R1.y, tmp.x, tmp.y, NULL);
     mpz_init_set(R0.x, point->x);

programming_language: C++