如何使用OpenSSL在Swift中防止由于错误输入d2i_X509_REQ_bio而导致致命错误

Uno*_*ome 3 error-handling openssl ios swift

内容:

我有以下代码将数据加载到BIO中,然后获得一个X509Req:

    let reqBIO = BIO_new(BIO_s_mem())
    let result = BIO_write(reqBIO, (reqData as NSData).bytes, Int32(reqData.count))
    let x509ReqContainer: UnsafeMutablePointer<X509_REQ> = d2i_X509_REQ_bio(reqBIO, nil)
    BIO_free(reqBIO) 
Run Code Online (Sandbox Code Playgroud)

当输入像预期的那样是base64编码的DER时,此代码非常有用。但是,如果我传递了base64Encoded垃圾字符串,它会炸毁并且很丑陋,并引发致命错误。

所以我的问题是:

  1. 我可以调用OpenSSL中的某种方法来确定BIO是否可以安全地发送到d2i函数,以便在这种情况下可以正常地失败
  2. 有什么办法可以迅速捕捉到致命错误吗?(我猜不是)
  3. 还有其他方法可以验证我的base64字符串是否包含CSR

Mar*_*n R 5

简短版本: d2i_X509_REQ_bio()无效输入不会“引发错误”。它只是返回一个空指针。崩溃的原因是您(可能是无意间)强行打开了Swift中的可选组件。

较长版本: C函数

X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **x);
Run Code Online (Sandbox Code Playgroud)

在无效输入上返回空指针。此C函数映射为Swift

func d2i_X509_REQ_bio(...) -> UnsafeMutablePointer<X509_REQ>!
Run Code Online (Sandbox Code Playgroud)

使用“隐式展开的可选”(IUO)作为返回类型,并且空指针表示为nil。IUO几乎等同于“常规”(强)可选,唯一的区别是,如果类型检查器需要,则可以将其强制展开。这就是作业发生的情况

let x509ReqContainer: UnsafeMutablePointer<X509_REQ> = d2i_X509_REQ_bio(reqBIO, nil)
Run Code Online (Sandbox Code Playgroud)

因为该变量被声明为非可选。如果C函数由于输入无效而返回空指针,则Swift将Optional.nil被解包,并且程序会因运行时错误而终止。

解决方案:将可选绑定与if let(或guard let)结合使用,并让编译器自动推断类型:

if let x509ReqContainer = d2i_X509_REQ_bio(reqBIO, nil) {
    // success ...
} else {
    // failed ...
}
Run Code Online (Sandbox Code Playgroud)

备注:您可以 Data使用

let result = reqData.withUnsafeBytes {
    BIO_write(reqBIO, $0.baseAddress, Int32($0.count))
}
Run Code Online (Sandbox Code Playgroud)

而不是将其强制转换为NSData