#include "bee2/core/blob.h"
#include "bee2/core/err.h"
#include "bee2/core/der.h"
#include "bee2/core/mem.h"
#include "bee2/core/rng.h"
#include "bee2/core/util.h"
#include "bee2/crypto/belt.h"
#include "bee2/crypto/bign.h"
#include "bee2/crypto/bpki.h"
#define derEncStep(step, ptr, count)\
do {\
size_t _t = step;\
ASSERT(_t != SIZE_MAX);\
ptr = ptr ? ptr + _t : 0;\
count += _t;\
} while(0)\
#define derDecStep(step, ptr, count)\
do {\
size_t _t = step;\
if (_t == SIZE_MAX)\
return SIZE_MAX;\
ptr += _t, count -= _t;\
} while(0)\
static const char oid_belt_hash[] = "1.2.112.0.2.0.34.101.31.81";
static const char oid_bign_pubkey[] = "1.2.112.0.2.0.34.101.45.2.1";
static const char oid_bign_curve192v1[] = "1.2.112.0.2.0.34.101.45.3.0";
static const char oid_bign_curve256v1[] = "1.2.112.0.2.0.34.101.45.3.1";
static const char oid_bign_curve384v1[] = "1.2.112.0.2.0.34.101.45.3.2";
static const char oid_bign_curve512v1[] = "1.2.112.0.2.0.34.101.45.3.3";
static const char oid_bign_with_hbelt[] = "1.2.112.0.2.0.34.101.45.12";
static const char oid_bels_share[] = "1.2.112.0.2.0.34.101.60.11";
static const char oid_bels_m0128v1[] = "1.2.112.0.2.0.34.101.60.2.1";
static const char oid_bels_m0192v1[] = "1.2.112.0.2.0.34.101.60.2.2";
static const char oid_bels_m0256v1[] = "1.2.112.0.2.0.34.101.60.2.3";
static const char oid_id_pbes2[] = "1.2.840.113549.1.5.13";
static const char oid_id_pbkdf2[] = "1.2.840.113549.1.5.12";
static const char oid_belt_kwp256[] = "1.2.112.0.2.0.34.101.31.73";
static const char oid_hmac_hbelt[] = "1.2.112.0.2.0.34.101.47.12";
static size_t bpkiPrivkeyEnc(octet pki[], const octet privkey[],
size_t privkey_len)
{
der_anchor_t PKI[1];
der_anchor_t BignAlgId[1];
size_t count = 0;
ASSERT(privkey_len == 24 || privkey_len == 32 || privkey_len == 48 ||
privkey_len == 64);
ASSERT(memIsNullOrValid(privkey, privkey_len));
derEncStep(derSEQEncStart(PKI, pki, count), pki, count);
derEncStep(derSIZEEnc(pki, 0), pki, count);
derEncStep(derSEQEncStart(BignAlgId, pki, count), pki, count);
derEncStep(derOIDEnc(pki, oid_bign_pubkey), pki, count);
if (privkey_len == 24)
derEncStep(derOIDEnc(pki, oid_bign_curve192v1), pki, count);
else if (privkey_len == 32)
derEncStep(derOIDEnc(pki, oid_bign_curve256v1), pki, count);
else if (privkey_len == 48)
derEncStep(derOIDEnc(pki, oid_bign_curve384v1), pki, count);
else
derEncStep(derOIDEnc(pki, oid_bign_curve512v1), pki, count);
derEncStep(derSEQEncStop(pki, count, BignAlgId), pki, count);
derEncStep(derOCTEnc(pki, privkey, privkey_len), pki, count);
derEncStep(derSEQEncStop(pki, count, PKI), pki, count);
return count;
}
static size_t bpkiPrivkeyDec(octet privkey[], size_t* privkey_len,
const octet pki[], size_t count)
{
der_anchor_t PKI[1];
der_anchor_t BignAlgId[1];
const octet* ptr = pki;
size_t t, len;
derDecStep(derSEQDecStart(PKI, ptr, count), ptr, count);
derDecStep(derSIZEDec2(ptr, count, 0), ptr, count);
derDecStep(derSEQDecStart(BignAlgId, ptr, count), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_bign_pubkey), ptr, count);
if ((t = derOIDDec2(ptr, count, oid_bign_curve192v1)) != SIZE_MAX)
len = 24;
else if ((t = derOIDDec2(ptr, count, oid_bign_curve256v1)) != SIZE_MAX)
len = 32;
else if ((t = derOIDDec2(ptr, count, oid_bign_curve384v1)) != SIZE_MAX)
len = 48;
else if ((t = derOIDDec2(ptr, count, oid_bign_curve512v1)) != SIZE_MAX)
len = 64;
else
return SIZE_MAX;
ptr += t, count -= t;
derDecStep(derSEQDecStop(ptr, BignAlgId), ptr, count);
derDecStep(derOCTDec2(privkey, ptr, count, len), ptr, count);
derDecStep(derSEQDecStop(ptr, PKI), ptr, count);
if (privkey_len)
{
ASSERT(memIsValid(privkey_len, O_PER_S));
*privkey_len = len;
}
return ptr - pki;
}
static size_t bpkiShareEnc(octet pki[], const octet share[], size_t share_len)
{
der_anchor_t PKI[1];
der_anchor_t BelsAlgId[1];
size_t count = 0;
ASSERT(share_len == 17 || share_len == 25 || share_len == 33);
ASSERT(memIsNullOrValid(share, share_len));
ASSERT(!share || 1 <= share[0] && share[0] <= 16);
derEncStep(derSEQEncStart(PKI, pki, count), pki, count);
derEncStep(derSIZEEnc(pki, 0), pki, count);
derEncStep(derSEQEncStart(BelsAlgId, pki, count), pki, count);
derEncStep(derOIDEnc(pki, oid_bels_share), pki, count);
if (share_len == 17)
derEncStep(derOIDEnc(pki, oid_bels_m0128v1), pki, count);
else if (share_len == 25)
derEncStep(derOIDEnc(pki, oid_bels_m0192v1), pki, count);
else
derEncStep(derOIDEnc(pki, oid_bels_m0256v1), pki, count);
derEncStep(derSEQEncStop(pki, count, BelsAlgId), pki, count);
derEncStep(derOCTEnc(pki, share, share_len), pki, count);
derEncStep(derSEQEncStop(pki, count, PKI), pki, count);
return count;
}
static size_t bpkiShareDec(octet share[], size_t* share_len,
const octet pki[], size_t count)
{
der_anchor_t PKI[1];
der_anchor_t BelsAlgId[1];
const octet* ptr = pki;
size_t t, len;
derDecStep(derSEQDecStart(PKI, ptr, count), ptr, count);
derDecStep(derSIZEDec2(ptr, count, 0), ptr, count);
derDecStep(derSEQDecStart(BelsAlgId, ptr, count), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_bels_share), ptr, count);
if ((t = derOIDDec2(ptr, count, oid_bels_m0128v1)) != SIZE_MAX)
len = 17;
else if ((t = derOIDDec2(ptr, count, oid_bels_m0192v1)) != SIZE_MAX)
len = 25;
else if ((t = derOIDDec2(ptr, count, oid_bels_m0256v1)) != SIZE_MAX)
len = 33;
else
return SIZE_MAX;
ptr += t, count -= t;
derDecStep(derSEQDecStop(ptr, BelsAlgId), ptr, count);
derDecStep(derOCTDec2(share, ptr, count, len), ptr, count);
derDecStep(derSEQDecStop(ptr, PKI), ptr, count);
if (share_len)
{
ASSERT(memIsValid(share_len, O_PER_S));
*share_len = len;
}
return ptr - pki;
}
static size_t bpkiEdataEnc(octet epki[], const octet edata[], size_t edata_len,
const octet salt[8], size_t iter)
{
der_anchor_t EPKI[1];
der_anchor_t EncryptionAlgId[1];
der_anchor_t PBES2_params[1];
der_anchor_t PBKDF2AlgId[1];
der_anchor_t PBKDF2_params[1];
der_anchor_t PrfAlgId[1];
der_anchor_t BeltKwpAlgId[1];
size_t count = 0;
derEncStep(derSEQEncStart(EPKI, epki, count), epki, count);
derEncStep(derSEQEncStart(EncryptionAlgId, epki, count), epki, count);
derEncStep(derOIDEnc(epki, oid_id_pbes2), epki, count);
derEncStep(derSEQEncStart(PBES2_params, epki, count), epki, count);
derEncStep(derSEQEncStart(PBKDF2AlgId, epki, count), epki, count);
derEncStep(derOIDEnc(epki, oid_id_pbkdf2), epki, count);
derEncStep(derSEQEncStart(PBKDF2_params, epki, count), epki, count);
derEncStep(derOCTEnc(epki, salt, 8), epki, count);
derEncStep(derSIZEEnc(epki, iter), epki, count);
derEncStep(derSEQEncStart(PrfAlgId, epki, count), epki, count);
derEncStep(derOIDEnc(epki, oid_hmac_hbelt), epki, count);
derEncStep(derNULLEnc(epki), epki, count);
derEncStep(derSEQEncStop(epki, count, PrfAlgId), epki, count);
derEncStep(derSEQEncStop(epki, count, PBKDF2_params), epki, count);
derEncStep(derSEQEncStop(epki, count, PBKDF2AlgId), epki, count);
derEncStep(derSEQEncStart(BeltKwpAlgId, epki, count), epki, count);
derEncStep(derOIDEnc(epki, oid_belt_kwp256), epki, count);
derEncStep(derNULLEnc(epki), epki, count);
derEncStep(derSEQEncStop(epki, count, BeltKwpAlgId), epki, count);
derEncStep(derSEQEncStop(epki, count, PBES2_params), epki, count);
derEncStep(derSEQEncStop(epki, count, EncryptionAlgId), epki, count);
derEncStep(derOCTEnc(epki, edata, edata_len), epki, count);
derEncStep(derSEQEncStop(epki, count, EPKI), epki, count);
return count;
}
static size_t bpkiEdataDec(octet edata[], size_t* edata_len, octet salt[8],
size_t* iter, const octet epki[], size_t count)
{
der_anchor_t EPKI[1];
der_anchor_t EncryptionAlgId[1];
der_anchor_t PBES2_params[1];
der_anchor_t PBKDF2AlgId[1];
der_anchor_t PBKDF2_params[1];
der_anchor_t PrfAlgId[1];
der_anchor_t BeltKwpAlgId[1];
const octet* ptr = epki;
derDecStep(derSEQDecStart(EPKI, ptr, count), ptr, count);
derDecStep(derSEQDecStart(EncryptionAlgId, ptr, count), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_id_pbes2), ptr, count);
derDecStep(derSEQDecStart(PBES2_params, ptr, count), ptr, count);
derDecStep(derSEQDecStart(PBKDF2AlgId, ptr, count), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_id_pbkdf2), ptr, count);
derDecStep(derSEQDecStart(PBKDF2_params, ptr, count), ptr, count);
derDecStep(derOCTDec2(salt, ptr, count, 8), ptr, count);
derDecStep(derSIZEDec(iter, ptr, count), ptr, count);
derDecStep(derSEQDecStart(PrfAlgId, ptr, count), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_hmac_hbelt), ptr, count);
derDecStep(derNULLDec(ptr, count), ptr, count);
derDecStep(derSEQDecStop(ptr, PrfAlgId), ptr, count);
derDecStep(derSEQDecStop(ptr, PBKDF2_params), ptr, count);
derDecStep(derSEQDecStop(ptr, PBKDF2AlgId), ptr, count);
derDecStep(derSEQDecStart(BeltKwpAlgId, ptr, count), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_belt_kwp256), ptr, count);
derDecStep(derNULLDec(ptr, count), ptr, count);
derDecStep(derSEQDecStop(ptr, BeltKwpAlgId), ptr, count);
derDecStep(derSEQDecStop(ptr, PBES2_params), ptr, count);
derDecStep(derSEQDecStop(ptr, EncryptionAlgId), ptr, count);
derDecStep(derOCTDec(edata, edata_len, ptr, count), ptr, count);
derDecStep(derSEQDecStop(ptr, EPKI), ptr, count);
return ptr - epki;
}
err_t bpkiPrivkeyWrap(octet epki[], size_t* epki_len, const octet privkey[],
size_t privkey_len, const octet pwd[], size_t pwd_len,
const octet salt[8], size_t iter)
{
size_t pki_len, edata_len, count;
octet* key;
err_t code;
if (iter < 10000)
return ERR_BAD_INPUT;
if (privkey_len != 32 && privkey_len != 24 && privkey_len != 48 &&
privkey_len != 64)
return ERR_BAD_PRIVKEY;
pki_len = bpkiPrivkeyEnc(0, privkey, privkey_len);
if (pki_len == SIZE_MAX)
return ERR_BAD_FORMAT;
edata_len = pki_len + 16;
count = bpkiEdataEnc(0, 0, edata_len, 0, iter);
if (count == SIZE_MAX)
return ERR_BAD_FORMAT;
if (epki_len)
{
if (!memIsValid(epki_len, O_PER_S))
return ERR_BAD_INPUT;
*epki_len = count;
}
if (!epki)
return ERR_OK;
if (!memIsValid(privkey, privkey_len) ||
!memIsValid(epki, count) ||
!memIsValid(pwd, pwd_len) ||
!memIsValid(salt, 8))
return ERR_BAD_INPUT;
key = (octet*)blobCreate(32);
if (!key)
return ERR_OUTOFMEMORY;
code = beltPBKDF2(key, pwd, pwd_len, iter, salt, 8);
ERR_CALL_HANDLE(code, blobClose(key));
pki_len = bpkiPrivkeyEnc(epki + count - pki_len, privkey, privkey_len);
code = (pki_len != SIZE_MAX) ? ERR_OK : ERR_BAD_PRIVKEY;
ERR_CALL_HANDLE(code, (memWipe(epki, count), blobClose(key)));
code = beltKWPWrap(epki + count - pki_len - 16,
epki + count - pki_len, pki_len, 0, key, 32);
ERR_CALL_HANDLE(code, (memWipe(epki, count), blobClose(key)));
count = bpkiEdataEnc(epki, epki + count - edata_len, edata_len,
salt, iter);
code = (count != SIZE_MAX) ? ERR_OK : ERR_BAD_FORMAT;
ERR_CALL_HANDLE(code, (memWipe(epki, count), blobClose(key)));
blobClose(key);
return ERR_OK;
}
err_t bpkiPrivkeyUnwrap(octet privkey[], size_t* privkey_len,
const octet epki[], size_t epki_len, const octet pwd[], size_t pwd_len)
{
size_t edata_len, pki_len, count, iter;
void* state;
octet* salt;
octet* key;
octet* edata;
err_t code;
if (epki_len == SIZE_MAX || !memIsValid(epki, epki_len) ||
!memIsValid(pwd, pwd_len) ||
privkey_len && !memIsValid(privkey_len, O_PER_S))
return ERR_BAD_INPUT;
count = bpkiEdataDec(0, &edata_len, 0, 0, epki, epki_len);
if (count != epki_len)
return ERR_BAD_FORMAT;
state = blobCreate(8 + 32 + edata_len);
if (!state)
return ERR_OUTOFMEMORY;
salt = (octet*)state;
key = salt + 8;
edata = key + 32;
VERIFY(bpkiEdataDec(edata, 0, salt, &iter, epki, epki_len) == epki_len);
code = beltPBKDF2(key, pwd, pwd_len, iter, salt, 8);
ERR_CALL_HANDLE(code, blobClose(state));
code = beltKWPUnwrap(edata, edata, edata_len, 0, key, 32);
ERR_CALL_HANDLE(code, blobClose(state));
pki_len = edata_len - 16;
count = bpkiPrivkeyDec(privkey, &edata_len, edata, pki_len);
code = count == pki_len ? ERR_OK : ERR_BAD_FORMAT;
ERR_CALL_HANDLE(code, blobClose(state));
code = memIsNullOrValid(privkey, edata_len) ? ERR_OK : ERR_BAD_INPUT;
ERR_CALL_HANDLE(code, blobClose(state));
VERIFY(bpkiPrivkeyDec(privkey, privkey_len, edata, pki_len) == pki_len);
blobClose(state);
return code;
}
err_t bpkiShareWrap(octet epki[], size_t* epki_len, const octet share[],
size_t share_len, const octet pwd[], size_t pwd_len,
const octet salt[8], size_t iter)
{
size_t pki_len, edata_len, count;
octet* key;
err_t code;
if (iter < 10000)
return ERR_BAD_INPUT;
if (share_len != 17 && share_len != 25 && share_len != 33 ||
share && (!memIsValid(share, 1) || share[0] == 0 || share[0] > 16))
return ERR_BAD_SECKEY;
pki_len = bpkiShareEnc(0, share, share_len);
if (pki_len == SIZE_MAX)
return ERR_BAD_FORMAT;
edata_len = pki_len + 16;
count = bpkiEdataEnc(0, 0, edata_len, 0, iter);
if (count == SIZE_MAX)
return ERR_BAD_FORMAT;
if (epki_len)
{
if (!memIsValid(epki_len, O_PER_S))
return ERR_BAD_INPUT;
*epki_len = count;
}
if (!epki)
return ERR_OK;
if (!memIsValid(share, share_len) ||
!memIsValid(epki, count) ||
!memIsValid(pwd, pwd_len) ||
!memIsValid(salt, 8))
return ERR_BAD_INPUT;
key = (octet*)blobCreate(32);
if (!key)
return ERR_OUTOFMEMORY;
code = beltPBKDF2(key, pwd, pwd_len, iter, salt, 8);
ERR_CALL_HANDLE(code, blobClose(key));
pki_len = bpkiShareEnc(epki + count - pki_len, share, share_len);
code = (pki_len != SIZE_MAX) ? ERR_OK : ERR_BAD_PRIVKEY;
ERR_CALL_HANDLE(code, (memWipe(epki, count), blobClose(key)));
code = beltKWPWrap(epki + count - pki_len - 16,
epki + count - pki_len, pki_len, 0, key, 32);
ERR_CALL_HANDLE(code, (memWipe(epki, count), blobClose(key)));
count = bpkiEdataEnc(epki, epki + count - edata_len, edata_len,
salt, iter);
code = (count != SIZE_MAX) ? ERR_OK : ERR_BAD_FORMAT;
ERR_CALL_HANDLE(code, (memWipe(epki, count), blobClose(key)));
blobClose(key);
return ERR_OK;
}
err_t bpkiShareUnwrap(octet share[], size_t* share_len,
const octet epki[], size_t epki_len, const octet pwd[], size_t pwd_len)
{
size_t edata_len, pki_len, count, iter;
void* state;
octet* salt;
octet* key;
octet* edata;
err_t code;
if (epki_len == SIZE_MAX || !memIsValid(epki, epki_len) ||
!memIsValid(pwd, pwd_len) ||
share_len && !memIsValid(share_len, O_PER_S))
return ERR_BAD_INPUT;
count = bpkiEdataDec(0, &edata_len, 0, 0, epki, epki_len);
if (count != epki_len)
return ERR_BAD_FORMAT;
state = blobCreate(8 + 32 + edata_len);
if (!state)
return ERR_OUTOFMEMORY;
salt = (octet*)state;
key = salt + 8;
edata = key + 32;
VERIFY(bpkiEdataDec(edata, 0, salt, &iter, epki, epki_len) == epki_len);
code = beltPBKDF2(key, pwd, pwd_len, iter, salt, 8);
ERR_CALL_HANDLE(code, blobClose(state));
code = beltKWPUnwrap(edata, edata, edata_len, 0, key, 32);
ERR_CALL_HANDLE(code, blobClose(state));
pki_len = edata_len - 16;
count = bpkiShareDec(share, &edata_len, edata, pki_len);
code = count == pki_len ? ERR_OK : ERR_BAD_FORMAT;
ERR_CALL_HANDLE(code, blobClose(state));
code = memIsNullOrValid(share, edata_len) ? ERR_OK : ERR_BAD_INPUT;
ERR_CALL_HANDLE(code, blobClose(state));
VERIFY(bpkiShareDec(share, share_len, edata, pki_len) == pki_len);
code = (!share || 1 <= share[0] && share[0] <= 16) ?
ERR_OK : ERR_BAD_SHAREKEY;
blobClose(state);
return code;
}
typedef struct
{
size_t body_offset;
size_t body_len;
size_t pubkey_offset;
size_t sig_offset;
}
bpki_csr_info_t;
static size_t bpkiCSRDec(bpki_csr_info_t* ci, const octet csr[], size_t count)
{
der_anchor_t CertReq[1];
der_anchor_t CertReqInfo[1];
der_anchor_t SPKI[1];
der_anchor_t AlgId[1];
const octet* ptr = csr;
ASSERT(memIsValid(ci, sizeof(bpki_csr_info_t)));
ASSERT(memIsValid(csr, count));
derDecStep(derSEQDecStart(CertReq, ptr, count), ptr, count);
ci->body_offset = ptr - csr;
derDecStep(derSEQDecStart(CertReqInfo, ptr, count), ptr, count);
derDecStep(derSIZEDec2(ptr, count, 0), ptr, count);
derDecStep(derDec2(0, 0, ptr, count, 0x30), ptr, count);
derDecStep(derSEQDecStart(SPKI, ptr, count), ptr, count);
derDecStep(derSEQDecStart(AlgId, ptr, count), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_bign_pubkey), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_bign_curve256v1), ptr, count);
derDecStep(derSEQDecStop(ptr, AlgId), ptr, count);
derDecStep(derBITDec2(0, ptr, count, 512), ptr, count);
ci->pubkey_offset = ptr - csr - 64;
derDecStep(derSEQDecStop(ptr, SPKI), ptr, count);
derDecStep(derDec2(0, 0, ptr, count, 0xA0), ptr, count);
derDecStep(derSEQDecStop(ptr, CertReqInfo), ptr, count);
ci->body_len = ptr - csr - ci->body_offset;
derDecStep(derSEQDecStart(AlgId, ptr, count), ptr, count);
derDecStep(derOIDDec2(ptr, count, oid_bign_with_hbelt), ptr, count);
derDecStep(derNULLDec(ptr, count), ptr, count);
derDecStep(derSEQDecStop(ptr, AlgId), ptr, count);
derDecStep(derBITDec2(0, ptr, count, 384), ptr, count);
ci->sig_offset = ptr - csr - 48;
derDecStep(derSEQDecStop(ptr, CertReq), ptr, count);
return ptr - csr;
}
err_t bpkiCSRRewrap(octet csr[], size_t csr_len, const octet privkey[],
size_t privkey_len)
{
err_t code;
size_t count;
bpki_csr_info_t ci[1];
bign_params params[1];
octet oid_der[16];
size_t oid_len = sizeof(oid_der);
octet* hash;
if (privkey_len != 32)
return ERR_NOT_IMPLEMENTED;
if (!memIsValid(csr, csr_len) || !memIsValid(privkey, 32))
return ERR_BAD_INPUT;
count = bpkiCSRDec(ci, csr, csr_len);
if (count == SIZE_MAX || count != csr_len)
return ERR_BAD_FORMAT;
code = bignParamsStd(params, oid_bign_curve256v1);
ERR_CALL_CHECK(code);
code = bignPubkeyCalc(csr + ci->pubkey_offset, params, privkey);
ERR_CALL_CHECK(code);
if (rngIsValid())
rngStepR(csr + ci->sig_offset, 48, 0);
code = bignOidToDER(oid_der, &oid_len, oid_belt_hash);
ERR_CALL_CHECK(code);
if (!(hash = blobCreate(32)))
return ERR_OUTOFMEMORY;
code = beltHash(hash, csr + ci->body_offset, ci->body_len);
ERR_CALL_HANDLE(code, blobClose(hash));
code = bignSign2(csr + ci->sig_offset, params, oid_der, oid_len,
hash, privkey, csr + ci->sig_offset, 48);
blobClose(hash);
return code;
}
err_t bpkiCSRUnwrap(octet pubkey[], size_t* pubkey_len, const octet csr[],
size_t csr_len)
{
err_t code;
size_t count;
bpki_csr_info_t ci[1];
bign_params params[1];
octet oid_der[16];
size_t oid_len = sizeof(oid_der);
octet* hash;
if (!memIsValid(csr, csr_len))
return ERR_BAD_INPUT;
count = bpkiCSRDec(ci, csr, csr_len);
if (count == SIZE_MAX || count != csr_len)
return ERR_BAD_FORMAT;
code = bignParamsStd(params, oid_bign_curve256v1);
ERR_CALL_CHECK(code);
code = bignOidToDER(oid_der, &oid_len, oid_belt_hash);
ERR_CALL_CHECK(code);
if (!(hash = blobCreate(32)))
return ERR_OUTOFMEMORY;
code = beltHash(hash, csr + ci->body_offset, ci->body_len);
ERR_CALL_HANDLE(code, blobClose(hash));
code = bignVerify(params, oid_der, oid_len, hash, csr + ci->sig_offset,
csr + ci->pubkey_offset);
blobClose(hash);
ERR_CALL_CHECK(code);
if (pubkey_len)
{
ASSERT(memIsValid(pubkey_len, O_PER_S));
*pubkey_len = 64;
}
if (pubkey)
{
ASSERT(memIsValid(pubkey, 64));
memMove(pubkey, csr + ci->pubkey_offset, 64);
}
return ERR_OK;
}