使用环验证 ECDSA 签名时出现“未指定”错误

如何解决使用环验证 ECDSA 签名时出现“未指定”错误

在使用 ring 板条箱验证 ECDSA 签名时,我遇到了这个错误。

我是一个最小的可复制示例,在 Python 中有一个工作版本。我可以验证输入字节(在解析证书等之后)在两者中完全相同。

import base64

try:
    import ecdsa.util
    from cryptography import x509
    from cryptography.hazmat.primitives import serialization
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives.asymmetric import ec as cryptography_ec
    from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature
    from cryptography.hazmat.primitives.hashes import SHA384
except ImportError:
    print("Missing deps,install:\n\n\tpip install ecdsa cryptography")


CERT = """-----BEGIN CERTIFICATE-----
MIIDBjCCAougAwIBAgIIFiJLFfdxFlYwCgYIKoZIzj0EAwMwgaMxCzAJBgNVBAYT
AlVTMRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMS8wLQYDVQQLEyZNb3pp
bGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25pbmcgU2VydmljZTFFMEMGA1UEAww8Q29u
dGVudCBTaWduaW5nIEludGVybWVkaWF0ZS9lbWFpbEFkZHJlc3M9Zm94c2VjQG1v
emlsbGEuY29tMB4XDTIwMDYxNjE3MTYxNVoXDTIwMDkwNDE3MTYxNVowgakxCzAJ
BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFp
biBWaWV3MRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMRcwFQYDVQQLEw5D
bG91ZCBTZXJ2aWNlczE2MDQGA1UEAxMtcmVtb3RlLXNldHRpbmdzLmNvbnRlbnQt
c2lnbmF0dXJlLm1vemlsbGEub3JnMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEDmOX
N5IGlUqCvu6xkOKr020Eo3kY2uPdJO0ZihVUoglk1ktQPss184OajFOMKm/BJX4W
IsZUzQoRL8NgGfZDwBjT95Q87lhOWEWs5AU/nMXIYwDp7rpUPaUqw0QLMikdo4GD
MIGAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSME
GDAWgBSgHUoXT4zCKzVF8WPx2nBwp8744TA4BgNVHREEMTAvgi1yZW1vdGUtc2V0
dGluZ3MuY29udGVudC1zaWduYXR1cmUubW96aWxsYS5vcmcwCgYIKoZIzj0EAwMD
aQAwZgIxAJvyynyPqRmRMqf95FPH5xfcoT3jb/2LOkUifGDtjtZ338ScpT2glUK8
HszKVANqXQIxAIygMaeTiD9figEusmHMthBdFoIoHk31x4MHukAy+TWZ863X6/V2
6/ZrZMp6Wq/0ow==
-----END CERTIFICATE-----
"""

SIG = "oPRadsg_5wnnUXlRIjamXKPWyyGe4VLt-KR4-PJTK2hq4hF196L3nbvne1_7-HfpoVRR4BLsHWtnnt6700CTt5kNgwvrE8aJ3nXFa0vJBoOvIRco-vCt-rJ7acEu0IFG"

DATA = b"""Content-Signature:\x00{"data":[],"last_modified":"1594998798350"}"""

# Parse X509 certificate
cert = x509.load_pem_x509_certificate(CERT.encode("utf8"),backend=default_backend())


signature = base64.urlsafe_b64decode(SIG)
r,s = ecdsa.util.sigdecode_string(
    signature,order=ecdsa.curves.NIST384p.order
)
signature_dss = encode_dss_signature(r,s)

algorithm = cryptography_ec.ECDSA(SHA384())

cert.public_key().verify(signature_dss,DATA,algorithm)

print("SUCCESS!")
print("PK:\t",cert.public_key().public_bytes(encoding=serialization.Encoding.X962,format=serialization.PublicFormat.UncompressedPoint).hex())
print("Sig:\t",signature.hex())
print("Data:\t",DATA.hex())

使用 ring(和 x509-parser),它看起来像这样,对 verify() 的调用失败并显示 Unspecified 错误,这不是很有帮助({{3} }):

use base64;
use ring::signature;
use x509_parser;

const CERTIFICATE: &str = r#"-----BEGIN CERTIFICATE-----
MIIDBjCCAougAwIBAgIIFiJLFfdxFlYwCgYIKoZIzj0EAwMwgaMxCzAJBgNVBAYT
AlVTMRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMS8wLQYDVQQLEyZNb3pp
bGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25pbmcgU2VydmljZTFFMEMGA1UEAww8Q29u
dGVudCBTaWduaW5nIEludGVybWVkaWF0ZS9lbWFpbEFkZHJlc3M9Zm94c2VjQG1v
emlsbGEuY29tMB4XDTIwMDYxNjE3MTYxNVoXDTIwMDkwNDE3MTYxNVowgakxCzAJ
BgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFp
biBWaWV3MRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMRcwFQYDVQQLEw5D
bG91ZCBTZXJ2aWNlczE2MDQGA1UEAxMtcmVtb3RlLXNldHRpbmdzLmNvbnRlbnQt
c2lnbmF0dXJlLm1vemlsbGEub3JnMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEDmOX
N5IGlUqCvu6xkOKr020Eo3kY2uPdJO0ZihVUoglk1ktQPss184OajFOMKm/BJX4W
IsZUzQoRL8NgGfZDwBjT95Q87lhOWEWs5AU/nMXIYwDp7rpUPaUqw0QLMikdo4GD
MIGAMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSME
GDAWgBSgHUoXT4zCKzVF8WPx2nBwp8744TA4BgNVHREEMTAvgi1yZW1vdGUtc2V0
dGluZ3MuY29udGVudC1zaWduYXR1cmUubW96aWxsYS5vcmcwCgYIKoZIzj0EAwMD
aQAwZgIxAJvyynyPqRmRMqf95FPH5xfcoT3jb/2LOkUifGDtjtZ338ScpT2glUK8
HszKVANqXQIxAIygMaeTiD9figEusmHMthBdFoIoHk31x4MHukAy+TWZ863X6/V2
6/ZrZMp6Wq/0ow==
-----END CERTIFICATE-----"#;

const SIGNATURE: &str = r#"oPRadsg_5wnnUXlRIjamXKPWyyGe4VLt-KR4-PJTK2hq4hF196L3nbvne1_7-HfpoVRR4BLsHWtnnt6700CTt5kNgwvrE8aJ3nXFa0vJBoOvIRco-vCt-rJ7acEu0IFG"#;

const DATA: &str = r#"Content-Signature:\x00{"data":[],"last_modified":"1594998798350"}"#;

macro_rules! hex {
    ($b: expr) => {
        {
            let ss: Vec<String> = $b.iter()
                .map(|b| format!("{:02x}",b))
                .collect();
            ss.join("")
        }
    };
}

fn main() {
    let pem = match x509_parser::pem::parse_x509_pem(CERTIFICATE.as_bytes()) {
        Ok((rem,pem)) => {
            assert!(rem.is_empty());
            //
            assert_eq!(pem.label,String::from("CERTIFICATE"));
            //
            pem
        },err => panic!("PEM parsing failed: {:?}",err),};

    let x509 = match x509_parser::parse_x509_certificate(&pem.contents) {
        Ok((rem,x509)) => {
            assert!(rem.is_empty());
            x509
        },err => panic!("X509 parsing failed: {:?}",};

    let spki = x509.tbs_certificate.subject_pki;
    let public_key = signature::UnparsedPublicKey::new(
        &signature::ECDSA_P384_SHA384_ASN1,&spki.subject_public_key.data,);

    let signature_bytes = base64::decode_config(&SIGNATURE,base64::URL_SAFE).unwrap();

    println!("PK:\t{}",hex!(spki.subject_public_key.data));
    println!("Sig:\t{}",hex!(signature_bytes));
    println!("Data:\t{}",hex!(DATA.as_bytes()));

    match public_key.verify(&DATA.as_bytes(),&signature_bytes) {
        Ok(_) => (),Err(err) => println!("ERROR {:?}",}
}

使用 openssl x509 -inform PEM -in cert.pem -text 我还可以确保公钥是 ASN1,并且字节也匹配。

有什么明显我遗漏的地方吗?

我该怎么做才能更深入地了解错误?

谢谢!

解决方法

我想通了。

首先,在python示例中,打印的签名不是传递给verify()的签名。应该是 print("Sig:\t",signature_dss.hex())

第二,在 Rust 中,Content-Signature:\x00 部分不应该是 DATA 中的原始字符串。例如,它可以是 let payload = format!("Content-Signature:\x00{}",r#"{"data":[],"last_modified":"1594998798350"}"#);

最后,最重要的是,我们也必须在 Rust 中将签名点值编码为 DER(相当于 Python 端的 encode_dss_signature())。由于 der_writer 中的 ring 模块 is not public,我最终实现了一个快速的特定模块:

use ring::io::der;

fn encode_dss_signature(signature_bytes: Vec<u8>) -> Vec<u8> {
    // Split the signature in two integers (48 bytes each)
    let sig_len = signature_bytes.len();
    let r_bytes = &signature_bytes[0..sig_len / 2];
    let s_bytes = &signature_bytes[sig_len / 2..];

    // Encode the two integer points.
    // See https://github.com/briansmith/ring/blob/3b1ece4/src/io/der_writer.rs
    let mut tuple_der: Vec<u8> = Vec::new();
    for val in [r_bytes,s_bytes].iter() {
        tuple_der.push(der::Tag::Integer as u8);
        tuple_der.push((val.len() + 1) as u8);
        if (val[0] & 0x80) != 0 {
            // Disambiguate negative number.
            tuple_der.push(0x00);
        }
        tuple_der.extend(*val);
    }

    // Sequence tag followed by content length and bytes.
    let mut signature_der: Vec<u8> = Vec::new();
    signature_der.push(der::Tag::Sequence as u8);
    signature_der.push(tuple_der.len() as u8);
    signature_der.extend(tuple_der);

    signature_der
}

现在可以成功验证签名了!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-