1241 lines
53 KiB
Zig
1241 lines
53 KiB
Zig
// ©AngelaMos | 2026
|
|
// crypto_ops.zig
|
|
|
|
const std = @import("std");
|
|
const ck = @import("../ck.zig");
|
|
const config = @import("../config.zig");
|
|
const state = @import("../core/state.zig");
|
|
const session = @import("../core/session.zig");
|
|
const object_store = @import("../core/object_store.zig");
|
|
const digest = @import("../crypto/digest.zig");
|
|
const mac = @import("../crypto/mac.zig");
|
|
const cipher = @import("../crypto/cipher.zig");
|
|
const ecdsa = @import("../crypto/ecdsa.zig");
|
|
const rsa = @import("../crypto/rsa.zig");
|
|
|
|
fn part(p: [*]ck.CK_BYTE, len: ck.CK_ULONG) []const u8 {
|
|
return p[0..@intCast(len)];
|
|
}
|
|
|
|
fn ctEql(a: []const u8, b: []const u8) bool {
|
|
if (a.len != b.len) return false;
|
|
var diff: u8 = 0;
|
|
for (a, b) |x, y| diff |= x ^ y;
|
|
return diff == 0;
|
|
}
|
|
|
|
fn objectClass(obj: *const object_store.Object) ?ck.CK_OBJECT_CLASS {
|
|
const v = obj.get(ck.CKA_CLASS) orelse return null;
|
|
if (v.len != @sizeOf(ck.CK_OBJECT_CLASS)) return null;
|
|
return std.mem.bytesToValue(ck.CK_OBJECT_CLASS, v[0..@sizeOf(ck.CK_OBJECT_CLASS)]);
|
|
}
|
|
|
|
fn keyType(obj: *const object_store.Object) ?ck.CK_KEY_TYPE {
|
|
const v = obj.get(ck.CKA_KEY_TYPE) orelse return null;
|
|
if (v.len != @sizeOf(ck.CK_KEY_TYPE)) return null;
|
|
return std.mem.bytesToValue(ck.CK_KEY_TYPE, v[0..@sizeOf(ck.CK_KEY_TYPE)]);
|
|
}
|
|
|
|
const KeyVal = union(enum) {
|
|
ok: []const u8,
|
|
err: ck.CK_RV,
|
|
};
|
|
|
|
fn secretKeyValue(inst: *state.Instance, hKey: ck.CK_OBJECT_HANDLE, usage: ck.CK_ATTRIBUTE_TYPE) KeyVal {
|
|
const obj = inst.objects.getPtr(hKey) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (!object_store.visible(obj, inst.logged_in)) return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (objectClass(obj) != ck.CKO_SECRET_KEY) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (obj.has(usage) and !obj.getBool(usage)) return .{ .err = ck.CKR_KEY_FUNCTION_NOT_PERMITTED };
|
|
const a = obj.findPtr(ck.CKA_VALUE) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (a.sealed) return .{ .err = ck.CKR_USER_NOT_LOGGED_IN };
|
|
return .{ .ok = a.value };
|
|
}
|
|
|
|
const EcKey = union(enum) {
|
|
ok: struct { curve: ecdsa.Curve, material: []const u8 },
|
|
err: ck.CK_RV,
|
|
};
|
|
|
|
fn ecPrivateKey(inst: *state.Instance, hKey: ck.CK_OBJECT_HANDLE) EcKey {
|
|
const obj = inst.objects.getPtr(hKey) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (!object_store.visible(obj, inst.logged_in)) return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (objectClass(obj) != ck.CKO_PRIVATE_KEY) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (keyType(obj) != ck.CKK_EC) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (obj.has(ck.CKA_SIGN) and !obj.getBool(ck.CKA_SIGN)) return .{ .err = ck.CKR_KEY_FUNCTION_NOT_PERMITTED };
|
|
const params = obj.get(ck.CKA_EC_PARAMS) orelse return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
const curve = ecdsa.curveFromParams(params) orelse return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
const sa = obj.findPtr(ck.CKA_VALUE) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (sa.sealed) return .{ .err = ck.CKR_USER_NOT_LOGGED_IN };
|
|
if (sa.value.len != curve.scalarLen()) return .{ .err = ck.CKR_FUNCTION_FAILED };
|
|
return .{ .ok = .{ .curve = curve, .material = sa.value } };
|
|
}
|
|
|
|
fn ecPublicKey(inst: *state.Instance, hKey: ck.CK_OBJECT_HANDLE) EcKey {
|
|
const obj = inst.objects.getPtr(hKey) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (!object_store.visible(obj, inst.logged_in)) return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (objectClass(obj) != ck.CKO_PUBLIC_KEY) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (keyType(obj) != ck.CKK_EC) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (obj.has(ck.CKA_VERIFY) and !obj.getBool(ck.CKA_VERIFY)) return .{ .err = ck.CKR_KEY_FUNCTION_NOT_PERMITTED };
|
|
const params = obj.get(ck.CKA_EC_PARAMS) orelse return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
const curve = ecdsa.curveFromParams(params) orelse return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
const der = obj.get(ck.CKA_EC_POINT) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
const point = ecdsa.unwrapEcPoint(der) orelse return .{ .err = ck.CKR_FUNCTION_FAILED };
|
|
if (point.len != curve.pointLen()) return .{ .err = ck.CKR_FUNCTION_FAILED };
|
|
return .{ .ok = .{ .curve = curve, .material = point } };
|
|
}
|
|
|
|
const RsaPriv = union(enum) {
|
|
ok: rsa.PrivateComponents,
|
|
err: ck.CK_RV,
|
|
};
|
|
|
|
const RsaPub = union(enum) {
|
|
ok: rsa.PublicComponents,
|
|
err: ck.CK_RV,
|
|
};
|
|
|
|
fn rsaPrivateComponents(inst: *state.Instance, hKey: ck.CK_OBJECT_HANDLE, usage: ck.CK_ATTRIBUTE_TYPE) RsaPriv {
|
|
const obj = inst.objects.getPtr(hKey) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (!object_store.visible(obj, inst.logged_in)) return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (objectClass(obj) != ck.CKO_PRIVATE_KEY) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (keyType(obj) != ck.CKK_RSA) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (obj.has(usage) and !obj.getBool(usage)) return .{ .err = ck.CKR_KEY_FUNCTION_NOT_PERMITTED };
|
|
if (obj.findPtr(ck.CKA_PRIVATE_EXPONENT)) |da| {
|
|
if (da.sealed) return .{ .err = ck.CKR_USER_NOT_LOGGED_IN };
|
|
}
|
|
return .{ .ok = .{
|
|
.n = obj.get(ck.CKA_MODULUS) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
.e = obj.get(ck.CKA_PUBLIC_EXPONENT) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
.d = obj.get(ck.CKA_PRIVATE_EXPONENT) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
.p = obj.get(ck.CKA_PRIME_1) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
.q = obj.get(ck.CKA_PRIME_2) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
.dmp1 = obj.get(ck.CKA_EXPONENT_1) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
.dmq1 = obj.get(ck.CKA_EXPONENT_2) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
.iqmp = obj.get(ck.CKA_COEFFICIENT) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
} };
|
|
}
|
|
|
|
fn rsaPublicComponents(inst: *state.Instance, hKey: ck.CK_OBJECT_HANDLE, usage: ck.CK_ATTRIBUTE_TYPE) RsaPub {
|
|
const obj = inst.objects.getPtr(hKey) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (!object_store.visible(obj, inst.logged_in)) return .{ .err = ck.CKR_KEY_HANDLE_INVALID };
|
|
if (objectClass(obj) != ck.CKO_PUBLIC_KEY) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (keyType(obj) != ck.CKK_RSA) return .{ .err = ck.CKR_KEY_TYPE_INCONSISTENT };
|
|
if (obj.has(usage) and !obj.getBool(usage)) return .{ .err = ck.CKR_KEY_FUNCTION_NOT_PERMITTED };
|
|
return .{ .ok = .{
|
|
.n = obj.get(ck.CKA_MODULUS) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
.e = obj.get(ck.CKA_PUBLIC_EXPONENT) orelse return .{ .err = ck.CKR_KEY_HANDLE_INVALID },
|
|
} };
|
|
}
|
|
|
|
fn isRsaSignMech(mech: ck.CK_MECHANISM_TYPE) bool {
|
|
return switch (mech) {
|
|
ck.CKM_RSA_PKCS, ck.CKM_SHA256_RSA_PKCS, ck.CKM_RSA_PKCS_PSS, ck.CKM_SHA256_RSA_PKCS_PSS => true,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
fn mgfHash(mgf: ck.CK_RSA_PKCS_MGF_TYPE) ?rsa.Hash {
|
|
return switch (mgf) {
|
|
ck.CKG_MGF1_SHA256 => .sha256,
|
|
ck.CKG_MGF1_SHA384 => .sha384,
|
|
ck.CKG_MGF1_SHA512 => .sha512,
|
|
else => null,
|
|
};
|
|
}
|
|
|
|
const SignParamsResult = union(enum) {
|
|
ok: rsa.SignParams,
|
|
err: ck.CK_RV,
|
|
};
|
|
|
|
fn parsePss(pMechanism: *ck.CK_MECHANISM, digest_hash: rsa.Hash) SignParamsResult {
|
|
var params: rsa.SignParams = .{
|
|
.scheme = .pss,
|
|
.digest = digest_hash,
|
|
.pss_hash = if (digest_hash == .none) .sha256 else digest_hash,
|
|
};
|
|
const p = pMechanism.pParameter orelse {
|
|
if (digest_hash == .none) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
return .{ .ok = params };
|
|
};
|
|
if (pMechanism.ulParameterLen != @sizeOf(ck.CK_RSA_PKCS_PSS_PARAMS)) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
const pp: *const ck.CK_RSA_PKCS_PSS_PARAMS = @ptrCast(@alignCast(p));
|
|
const h = rsa.Hash.fromMech(pp.hashAlg) orelse return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (digest_hash != .none and h != digest_hash) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (mgfHash(pp.mgf) != h) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (pp.sLen > rsa.max_modulus_bytes) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
params.pss_hash = h;
|
|
params.salt_len = @intCast(pp.sLen);
|
|
return .{ .ok = params };
|
|
}
|
|
|
|
fn rsaSignParams(pMechanism: *ck.CK_MECHANISM) SignParamsResult {
|
|
return switch (pMechanism.mechanism) {
|
|
ck.CKM_RSA_PKCS => .{ .ok = .{ .scheme = .pkcs1, .digest = .none } },
|
|
ck.CKM_SHA256_RSA_PKCS => .{ .ok = .{ .scheme = .pkcs1, .digest = .sha256 } },
|
|
ck.CKM_RSA_PKCS_PSS => parsePss(pMechanism, .none),
|
|
ck.CKM_SHA256_RSA_PKCS_PSS => parsePss(pMechanism, .sha256),
|
|
else => .{ .err = ck.CKR_MECHANISM_INVALID },
|
|
};
|
|
}
|
|
|
|
const CryptParamsResult = union(enum) {
|
|
ok: rsa.CryptParams,
|
|
err: ck.CK_RV,
|
|
};
|
|
|
|
fn rsaCryptParams(pMechanism: *ck.CK_MECHANISM) CryptParamsResult {
|
|
return switch (pMechanism.mechanism) {
|
|
ck.CKM_RSA_PKCS => .{ .ok = .{ .scheme = .pkcs1 } },
|
|
ck.CKM_RSA_PKCS_OAEP => blk: {
|
|
const p = pMechanism.pParameter orelse break :blk .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (pMechanism.ulParameterLen != @sizeOf(ck.CK_RSA_PKCS_OAEP_PARAMS)) break :blk .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
const op: *const ck.CK_RSA_PKCS_OAEP_PARAMS = @ptrCast(@alignCast(p));
|
|
const h = rsa.Hash.fromMech(op.hashAlg) orelse break :blk .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (mgfHash(op.mgf) != h) break :blk .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (op.ulSourceDataLen != 0) break :blk .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
break :blk .{ .ok = .{ .scheme = .oaep, .oaep_hash = h } };
|
|
},
|
|
else => .{ .err = ck.CKR_MECHANISM_INVALID },
|
|
};
|
|
}
|
|
|
|
fn signLen(op: *const session.SignOp) ck.CK_ULONG {
|
|
return switch (op.*) {
|
|
.mac => |*m| @intCast(m.macLen()),
|
|
.ec => |*e| @intCast(e.sigLen()),
|
|
.rsa => |*r| @intCast(r.sig_len),
|
|
};
|
|
}
|
|
|
|
fn emitSign(inst: *state.Instance, sess: *session.Session, pSignature: ?[*]ck.CK_BYTE, pulSignatureLen: *ck.CK_ULONG) ck.CK_RV {
|
|
const op = &sess.sign_op.?;
|
|
const slen = signLen(op);
|
|
if (pSignature == null) {
|
|
pulSignatureLen.* = slen;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulSignatureLen.* < slen) {
|
|
pulSignatureLen.* = slen;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const out = pSignature.?[0..@intCast(slen)];
|
|
switch (op.*) {
|
|
.mac => |*m| m.finalInto(out),
|
|
.ec => |*e| _ = e.finalInto(inst.io(), out) catch {
|
|
sess.endSign();
|
|
return ck.CKR_FUNCTION_FAILED;
|
|
},
|
|
.rsa => return ck.CKR_FUNCTION_FAILED,
|
|
}
|
|
pulSignatureLen.* = slen;
|
|
sess.endSign();
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
fn finalizeVerify(sess: *session.Session, pSignature: [*]ck.CK_BYTE, ulSignatureLen: ck.CK_ULONG) ck.CK_RV {
|
|
const sig = pSignature[0..@intCast(ulSignatureLen)];
|
|
const rv = switch (sess.verify_op.?) {
|
|
.mac => |*m| blk: {
|
|
const mlen: ck.CK_ULONG = @intCast(m.macLen());
|
|
var computed: [mac.max_mac_len]u8 = undefined;
|
|
m.finalInto(computed[0..@intCast(mlen)]);
|
|
if (ulSignatureLen != mlen) break :blk ck.CKR_SIGNATURE_LEN_RANGE;
|
|
if (!ctEql(computed[0..@intCast(mlen)], sig)) break :blk ck.CKR_SIGNATURE_INVALID;
|
|
break :blk ck.CKR_OK;
|
|
},
|
|
.ec => |*e| switch (e.finalVerify(sig)) {
|
|
.ok => ck.CKR_OK,
|
|
.invalid => ck.CKR_SIGNATURE_INVALID,
|
|
.len_range => ck.CKR_SIGNATURE_LEN_RANGE,
|
|
},
|
|
.rsa => ck.CKR_FUNCTION_FAILED,
|
|
};
|
|
sess.endVerify();
|
|
return rv;
|
|
}
|
|
|
|
fn signInitOp(inst: *state.Instance, hKey: ck.CK_OBJECT_HANDLE, pMechanism: *ck.CK_MECHANISM) union(enum) { ok: session.SignOp, err: ck.CK_RV } {
|
|
const mech = pMechanism.mechanism;
|
|
if (mac.macLenOf(mech) != null) {
|
|
const val = switch (secretKeyValue(inst, hKey, ck.CKA_SIGN)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |v| v,
|
|
};
|
|
return .{ .ok = .{ .mac = mac.Mac.init(mech, val) orelse return .{ .err = ck.CKR_MECHANISM_INVALID } } };
|
|
}
|
|
if (ecdsa.hashModeOf(mech) != null) {
|
|
const k = switch (ecPrivateKey(inst, hKey)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |v| v,
|
|
};
|
|
return .{ .ok = .{ .ec = ecdsa.SignState.init(k.curve, mech, k.material) orelse return .{ .err = ck.CKR_MECHANISM_INVALID } } };
|
|
}
|
|
if (isRsaSignMech(mech)) {
|
|
const params = switch (rsaSignParams(pMechanism)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |p| p,
|
|
};
|
|
const pc = switch (rsaPrivateComponents(inst, hKey, ck.CKA_SIGN)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |c| c,
|
|
};
|
|
return .{ .ok = .{ .rsa = .{ .key = hKey, .params = params, .sig_len = pc.n.len } } };
|
|
}
|
|
return .{ .err = ck.CKR_MECHANISM_INVALID };
|
|
}
|
|
|
|
fn verifyInitOp(inst: *state.Instance, hKey: ck.CK_OBJECT_HANDLE, pMechanism: *ck.CK_MECHANISM) union(enum) { ok: session.VerifyOp, err: ck.CK_RV } {
|
|
const mech = pMechanism.mechanism;
|
|
if (mac.macLenOf(mech) != null) {
|
|
const val = switch (secretKeyValue(inst, hKey, ck.CKA_VERIFY)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |v| v,
|
|
};
|
|
return .{ .ok = .{ .mac = mac.Mac.init(mech, val) orelse return .{ .err = ck.CKR_MECHANISM_INVALID } } };
|
|
}
|
|
if (ecdsa.hashModeOf(mech) != null) {
|
|
const k = switch (ecPublicKey(inst, hKey)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |v| v,
|
|
};
|
|
return .{ .ok = .{ .ec = ecdsa.VerifyState.init(k.curve, mech, k.material) orelse return .{ .err = ck.CKR_MECHANISM_INVALID } } };
|
|
}
|
|
if (isRsaSignMech(mech)) {
|
|
const params = switch (rsaSignParams(pMechanism)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |p| p,
|
|
};
|
|
const pc = switch (rsaPublicComponents(inst, hKey, ck.CKA_VERIFY)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |c| c,
|
|
};
|
|
return .{ .ok = .{ .rsa = .{ .key = hKey, .params = params, .sig_len = pc.n.len } } };
|
|
}
|
|
return .{ .err = ck.CKR_MECHANISM_INVALID };
|
|
}
|
|
|
|
fn mapCipherErr(e: cipher.Error) ck.CK_RV {
|
|
return switch (e) {
|
|
cipher.Error.DataLenRange => ck.CKR_DATA_LEN_RANGE,
|
|
cipher.Error.EncryptedDataLenRange => ck.CKR_ENCRYPTED_DATA_LEN_RANGE,
|
|
cipher.Error.EncryptedDataInvalid => ck.CKR_ENCRYPTED_DATA_INVALID,
|
|
cipher.Error.KeySize => ck.CKR_KEY_SIZE_RANGE,
|
|
cipher.Error.AadTooLarge => ck.CKR_ARGUMENTS_BAD,
|
|
cipher.Error.IvInvalid => ck.CKR_MECHANISM_PARAM_INVALID,
|
|
};
|
|
}
|
|
|
|
const CipherInit = union(enum) {
|
|
ok: cipher.Cipher,
|
|
err: ck.CK_RV,
|
|
};
|
|
|
|
fn buildCipher(inst: *state.Instance, pMechanism: *ck.CK_MECHANISM, hKey: ck.CK_OBJECT_HANDLE, encrypt: bool, usage: ck.CK_ATTRIBUTE_TYPE) CipherInit {
|
|
const mode = cipher.modeOf(pMechanism.mechanism) orelse return .{ .err = ck.CKR_MECHANISM_INVALID };
|
|
const val = switch (secretKeyValue(inst, hKey, usage)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |v| v,
|
|
};
|
|
if (!cipher.validKeyLen(val.len)) return .{ .err = ck.CKR_KEY_SIZE_RANGE };
|
|
|
|
var c: cipher.Cipher = .{ .mode = mode, .encrypt = encrypt, .key_len = @intCast(val.len) };
|
|
@memcpy(c.key_buf[0..val.len], val);
|
|
|
|
switch (mode) {
|
|
.cbc, .cbc_pad => {
|
|
const p = pMechanism.pParameter orelse return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (pMechanism.ulParameterLen != config.aes_block_len) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
@memcpy(&c.chain, @as([*]const u8, @ptrCast(p))[0..config.aes_block_len]);
|
|
},
|
|
.gcm => {
|
|
const p = pMechanism.pParameter orelse return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (pMechanism.ulParameterLen != @sizeOf(ck.CK_GCM_PARAMS)) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
const gp: *const ck.CK_GCM_PARAMS = @ptrCast(@alignCast(p));
|
|
if (gp.ulIvLen != config.gcm_iv_len) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (gp.ulIvBits != 0 and gp.ulIvBits != config.gcm_iv_bits) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
if (gp.ulTagBits != config.gcm_tag_bits) return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
const ivp = gp.pIv orelse return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
@memcpy(&c.iv, ivp[0..config.gcm_iv_len]);
|
|
const aad_len: usize = @intCast(gp.ulAADLen);
|
|
if (aad_len > config.max_gcm_aad_len) return .{ .err = ck.CKR_ARGUMENTS_BAD };
|
|
if (aad_len > 0) {
|
|
const ap = gp.pAAD orelse return .{ .err = ck.CKR_MECHANISM_PARAM_INVALID };
|
|
@memcpy(c.aad_buf[0..aad_len], ap[0..aad_len]);
|
|
}
|
|
c.aad_len = aad_len;
|
|
},
|
|
}
|
|
return .{ .ok = c };
|
|
}
|
|
|
|
fn updateOutLen(op: *const cipher.Cipher, in_len: usize) ck.CK_ULONG {
|
|
return @intCast(((op.partial_len + in_len) / config.aes_block_len) * config.aes_block_len);
|
|
}
|
|
|
|
const NeedResult = union(enum) { ok: ck.CK_ULONG, err: ck.CK_RV };
|
|
const EmitResult = union(enum) { ok: usize, err: ck.CK_RV };
|
|
|
|
fn encUpdateNeed(op: *const session.EncryptOp, in_len: usize) NeedResult {
|
|
return switch (op.*) {
|
|
.rsa => .{ .err = ck.CKR_FUNCTION_NOT_SUPPORTED },
|
|
.aes => |*c| .{ .ok = updateOutLen(c, in_len) },
|
|
.gcm => .{ .ok = 0 },
|
|
};
|
|
}
|
|
|
|
fn encUpdateEmit(inst: *state.Instance, op: *session.EncryptOp, in: []const u8, out: []u8) EmitResult {
|
|
switch (op.*) {
|
|
.rsa => return .{ .err = ck.CKR_FUNCTION_NOT_SUPPORTED },
|
|
.aes => |*c| return .{ .ok = c.encryptUpdate(in, out) },
|
|
.gcm => |*g| {
|
|
g.append(inst.allocator(), in) catch |e| return .{ .err = switch (e) {
|
|
error.OutOfMemory => ck.CKR_HOST_MEMORY,
|
|
error.TooLarge => ck.CKR_DATA_LEN_RANGE,
|
|
} };
|
|
return .{ .ok = 0 };
|
|
},
|
|
}
|
|
}
|
|
|
|
fn decUpdateNeed(op: *const session.DecryptOp, in_len: usize) NeedResult {
|
|
return switch (op.*) {
|
|
.rsa => .{ .err = ck.CKR_FUNCTION_NOT_SUPPORTED },
|
|
.aes => |*c| .{ .ok = updateOutLen(c, in_len) },
|
|
.gcm => .{ .ok = 0 },
|
|
};
|
|
}
|
|
|
|
fn decUpdateEmit(inst: *state.Instance, op: *session.DecryptOp, in: []const u8, out: []u8) EmitResult {
|
|
switch (op.*) {
|
|
.rsa => return .{ .err = ck.CKR_FUNCTION_NOT_SUPPORTED },
|
|
.aes => |*c| return .{ .ok = c.decryptUpdate(in, out) },
|
|
.gcm => |*g| {
|
|
g.append(inst.allocator(), in) catch |e| return .{ .err = switch (e) {
|
|
error.OutOfMemory => ck.CKR_HOST_MEMORY,
|
|
error.TooLarge => ck.CKR_ENCRYPTED_DATA_LEN_RANGE,
|
|
} };
|
|
return .{ .ok = 0 };
|
|
},
|
|
}
|
|
}
|
|
|
|
fn decryptSideDualOk(op: *const session.DecryptOp) bool {
|
|
return switch (op.*) {
|
|
.aes => |*c| c.mode == .cbc,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
fn emitDigest(sess: *session.Session, pDigest: ?[*]ck.CK_BYTE, pulDigestLen: *ck.CK_ULONG) ck.CK_RV {
|
|
const op = &sess.digest_op.?;
|
|
const dlen: ck.CK_ULONG = @intCast(op.digestLen());
|
|
if (pDigest == null) {
|
|
pulDigestLen.* = dlen;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulDigestLen.* < dlen) {
|
|
pulDigestLen.* = dlen;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
op.finalInto(pDigest.?[0..@intCast(dlen)]);
|
|
pulDigestLen.* = dlen;
|
|
sess.endDigest();
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
fn isRsaCryptMech(mech: ck.CK_MECHANISM_TYPE) bool {
|
|
return mech == ck.CKM_RSA_PKCS or mech == ck.CKM_RSA_PKCS_OAEP;
|
|
}
|
|
|
|
const RsaCryptResult = union(enum) {
|
|
ok: session.RsaCrypt,
|
|
err: ck.CK_RV,
|
|
};
|
|
|
|
fn rsaCryptInit(inst: *state.Instance, pMechanism: *ck.CK_MECHANISM, hKey: ck.CK_OBJECT_HANDLE, private: bool, usage: ck.CK_ATTRIBUTE_TYPE) RsaCryptResult {
|
|
const params = switch (rsaCryptParams(pMechanism)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |p| p,
|
|
};
|
|
const mod_len = if (private) switch (rsaPrivateComponents(inst, hKey, usage)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |c| c.n.len,
|
|
} else switch (rsaPublicComponents(inst, hKey, usage)) {
|
|
.err => |rv| return .{ .err = rv },
|
|
.ok => |c| c.n.len,
|
|
};
|
|
return .{ .ok = .{ .key = hKey, .params = params, .out_len = mod_len } };
|
|
}
|
|
|
|
pub fn C_EncryptInit(hSession: ck.CK_SESSION_HANDLE, pMechanism: *ck.CK_MECHANISM, hKey: ck.CK_OBJECT_HANDLE) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.encrypt_op != null) return ck.CKR_OPERATION_ACTIVE;
|
|
if (cipher.modeOf(pMechanism.mechanism) != null) {
|
|
const c = switch (buildCipher(inst, pMechanism, hKey, true, ck.CKA_ENCRYPT)) {
|
|
.err => |rv| return rv,
|
|
.ok => |built| built,
|
|
};
|
|
sess.encrypt_op = if (c.mode == .gcm) .{ .gcm = .{ .cipher = c } } else .{ .aes = c };
|
|
return ck.CKR_OK;
|
|
}
|
|
if (isRsaCryptMech(pMechanism.mechanism)) {
|
|
sess.encrypt_op = .{ .rsa = switch (rsaCryptInit(inst, pMechanism, hKey, false, ck.CKA_ENCRYPT)) {
|
|
.err => |rv| return rv,
|
|
.ok => |o| o,
|
|
} };
|
|
return ck.CKR_OK;
|
|
}
|
|
return ck.CKR_MECHANISM_INVALID;
|
|
}
|
|
|
|
pub fn C_Encrypt(hSession: ck.CK_SESSION_HANDLE, pData: [*]ck.CK_BYTE, ulDataLen: ck.CK_ULONG, pEncryptedData: ?[*]ck.CK_BYTE, pulEncryptedDataLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
const op = if (sess.encrypt_op) |*o| o else return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const in = part(pData, ulDataLen);
|
|
|
|
switch (op.*) {
|
|
.aes => |*c| {
|
|
const need: ck.CK_ULONG = @intCast(cipher.encryptOutLen(c.mode, in.len));
|
|
if (pEncryptedData == null) {
|
|
pulEncryptedDataLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulEncryptedDataLen.* < need) {
|
|
pulEncryptedDataLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const out = pEncryptedData.?[0..@intCast(need)];
|
|
var n = c.encryptUpdate(in, out);
|
|
n += c.encryptFinal(out[n..]) catch |e| {
|
|
sess.endEncrypt(inst.allocator());
|
|
return mapCipherErr(e);
|
|
};
|
|
pulEncryptedDataLen.* = @intCast(n);
|
|
sess.endEncrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
.gcm => |*g| {
|
|
const need: ck.CK_ULONG = @intCast(cipher.encryptOutLen(.gcm, in.len));
|
|
if (pEncryptedData == null) {
|
|
pulEncryptedDataLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulEncryptedDataLen.* < need) {
|
|
pulEncryptedDataLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const n = g.cipher.gcmEncrypt(in, pEncryptedData.?[0..@intCast(need)]);
|
|
pulEncryptedDataLen.* = @intCast(n);
|
|
sess.endEncrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
.rsa => |*r| {
|
|
const need: ck.CK_ULONG = @intCast(r.out_len);
|
|
if (pEncryptedData == null) {
|
|
pulEncryptedDataLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulEncryptedDataLen.* < need) {
|
|
pulEncryptedDataLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const pc = switch (rsaPublicComponents(inst, r.key, ck.CKA_ENCRYPT)) {
|
|
.err => |rv| {
|
|
sess.endEncrypt(inst.allocator());
|
|
return rv;
|
|
},
|
|
.ok => |c| c,
|
|
};
|
|
const n = rsa.encrypt(pc, r.params, in, pEncryptedData.?[0..@intCast(need)]) catch {
|
|
sess.endEncrypt(inst.allocator());
|
|
return ck.CKR_DATA_LEN_RANGE;
|
|
};
|
|
pulEncryptedDataLen.* = @intCast(n);
|
|
sess.endEncrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn C_EncryptUpdate(hSession: ck.CK_SESSION_HANDLE, pPart: [*]ck.CK_BYTE, ulPartLen: ck.CK_ULONG, pEncryptedPart: ?[*]ck.CK_BYTE, pulEncryptedPartLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
const op = if (sess.encrypt_op) |*o| o else return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const in = part(pPart, ulPartLen);
|
|
const need = switch (encUpdateNeed(op, in.len)) {
|
|
.err => |rv| return rv,
|
|
.ok => |n| n,
|
|
};
|
|
if (pEncryptedPart == null) {
|
|
pulEncryptedPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulEncryptedPartLen.* < need) {
|
|
pulEncryptedPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const wrote = switch (encUpdateEmit(inst, op, in, pEncryptedPart.?[0..@intCast(need)])) {
|
|
.err => |rv| {
|
|
sess.endEncrypt(inst.allocator());
|
|
return rv;
|
|
},
|
|
.ok => |n| n,
|
|
};
|
|
pulEncryptedPartLen.* = @intCast(wrote);
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_EncryptFinal(hSession: ck.CK_SESSION_HANDLE, pLastEncryptedPart: ?[*]ck.CK_BYTE, pulLastEncryptedPartLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
const op = if (sess.encrypt_op) |*o| o else return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
switch (op.*) {
|
|
.rsa => return ck.CKR_FUNCTION_NOT_SUPPORTED,
|
|
.aes => |*c| {
|
|
const need: ck.CK_ULONG = if (c.mode == .cbc_pad) config.aes_block_len else 0;
|
|
if (pLastEncryptedPart == null) {
|
|
pulLastEncryptedPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulLastEncryptedPartLen.* < need) {
|
|
pulLastEncryptedPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const n = c.encryptFinal(pLastEncryptedPart.?[0..@intCast(need)]) catch |e| {
|
|
sess.endEncrypt(inst.allocator());
|
|
return mapCipherErr(e);
|
|
};
|
|
pulLastEncryptedPartLen.* = @intCast(n);
|
|
sess.endEncrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
.gcm => |*g| {
|
|
const need: ck.CK_ULONG = @intCast(g.len + config.gcm_tag_len);
|
|
if (pLastEncryptedPart == null) {
|
|
pulLastEncryptedPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulLastEncryptedPartLen.* < need) {
|
|
pulLastEncryptedPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const n = g.cipher.gcmEncrypt(g.data(), pLastEncryptedPart.?[0..@intCast(need)]);
|
|
pulLastEncryptedPartLen.* = @intCast(n);
|
|
sess.endEncrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn C_DecryptInit(hSession: ck.CK_SESSION_HANDLE, pMechanism: *ck.CK_MECHANISM, hKey: ck.CK_OBJECT_HANDLE) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.decrypt_op != null) return ck.CKR_OPERATION_ACTIVE;
|
|
if (cipher.modeOf(pMechanism.mechanism) != null) {
|
|
const c = switch (buildCipher(inst, pMechanism, hKey, false, ck.CKA_DECRYPT)) {
|
|
.err => |rv| return rv,
|
|
.ok => |built| built,
|
|
};
|
|
sess.decrypt_op = if (c.mode == .gcm) .{ .gcm = .{ .cipher = c } } else .{ .aes = c };
|
|
return ck.CKR_OK;
|
|
}
|
|
if (isRsaCryptMech(pMechanism.mechanism)) {
|
|
sess.decrypt_op = .{ .rsa = switch (rsaCryptInit(inst, pMechanism, hKey, true, ck.CKA_DECRYPT)) {
|
|
.err => |rv| return rv,
|
|
.ok => |o| o,
|
|
} };
|
|
return ck.CKR_OK;
|
|
}
|
|
return ck.CKR_MECHANISM_INVALID;
|
|
}
|
|
|
|
pub fn C_Decrypt(hSession: ck.CK_SESSION_HANDLE, pEncryptedData: [*]ck.CK_BYTE, ulEncryptedDataLen: ck.CK_ULONG, pData: ?[*]ck.CK_BYTE, pulDataLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
const op = if (sess.decrypt_op) |*o| o else return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const in = part(pEncryptedData, ulEncryptedDataLen);
|
|
|
|
switch (op.*) {
|
|
.aes => |*c| {
|
|
const need: ck.CK_ULONG = @intCast(cipher.decryptOutLen(c.mode, in.len));
|
|
if (pData == null) {
|
|
pulDataLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulDataLen.* < need) {
|
|
pulDataLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const out = pData.?[0..@intCast(need)];
|
|
var n = c.decryptUpdate(in, out);
|
|
n += c.decryptFinal(out[n..]) catch |e| {
|
|
sess.endDecrypt(inst.allocator());
|
|
return mapCipherErr(e);
|
|
};
|
|
pulDataLen.* = @intCast(n);
|
|
sess.endDecrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
.gcm => |*g| {
|
|
const need: ck.CK_ULONG = @intCast(cipher.decryptOutLen(.gcm, in.len));
|
|
if (pData == null) {
|
|
pulDataLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulDataLen.* < need) {
|
|
pulDataLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const n = g.cipher.gcmDecrypt(in, pData.?[0..@intCast(need)]) catch |e| {
|
|
sess.endDecrypt(inst.allocator());
|
|
return mapCipherErr(e);
|
|
};
|
|
pulDataLen.* = @intCast(n);
|
|
sess.endDecrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
.rsa => |*r| {
|
|
const need: ck.CK_ULONG = @intCast(r.out_len);
|
|
if (pData == null) {
|
|
pulDataLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulDataLen.* < need) {
|
|
pulDataLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const sc = switch (rsaPrivateComponents(inst, r.key, ck.CKA_DECRYPT)) {
|
|
.err => |rv| {
|
|
sess.endDecrypt(inst.allocator());
|
|
return rv;
|
|
},
|
|
.ok => |c| c,
|
|
};
|
|
const n = rsa.decrypt(sc, r.params, in, pData.?[0..@intCast(need)]) catch {
|
|
sess.endDecrypt(inst.allocator());
|
|
return ck.CKR_ENCRYPTED_DATA_INVALID;
|
|
};
|
|
pulDataLen.* = @intCast(n);
|
|
sess.endDecrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn C_DecryptUpdate(hSession: ck.CK_SESSION_HANDLE, pEncryptedPart: [*]ck.CK_BYTE, ulEncryptedPartLen: ck.CK_ULONG, pPart: ?[*]ck.CK_BYTE, pulPartLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
const op = if (sess.decrypt_op) |*o| o else return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const in = part(pEncryptedPart, ulEncryptedPartLen);
|
|
const need = switch (decUpdateNeed(op, in.len)) {
|
|
.err => |rv| return rv,
|
|
.ok => |n| n,
|
|
};
|
|
if (pPart == null) {
|
|
pulPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulPartLen.* < need) {
|
|
pulPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const wrote = switch (decUpdateEmit(inst, op, in, pPart.?[0..@intCast(need)])) {
|
|
.err => |rv| {
|
|
sess.endDecrypt(inst.allocator());
|
|
return rv;
|
|
},
|
|
.ok => |n| n,
|
|
};
|
|
pulPartLen.* = @intCast(wrote);
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_DecryptFinal(hSession: ck.CK_SESSION_HANDLE, pLastPart: ?[*]ck.CK_BYTE, pulLastPartLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
const op = if (sess.decrypt_op) |*o| o else return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
switch (op.*) {
|
|
.rsa => return ck.CKR_FUNCTION_NOT_SUPPORTED,
|
|
.aes => |*c| {
|
|
const need: ck.CK_ULONG = if (c.mode == .cbc_pad) config.aes_block_len else 0;
|
|
if (pLastPart == null) {
|
|
pulLastPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulLastPartLen.* < need) {
|
|
pulLastPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const n = c.decryptFinal(pLastPart.?[0..@intCast(need)]) catch |e| {
|
|
sess.endDecrypt(inst.allocator());
|
|
return mapCipherErr(e);
|
|
};
|
|
pulLastPartLen.* = @intCast(n);
|
|
sess.endDecrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
.gcm => |*g| {
|
|
const need: ck.CK_ULONG = @intCast(cipher.decryptOutLen(.gcm, g.len));
|
|
if (pLastPart == null) {
|
|
pulLastPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulLastPartLen.* < need) {
|
|
pulLastPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const n = g.cipher.gcmDecrypt(g.data(), pLastPart.?[0..@intCast(need)]) catch |e| {
|
|
sess.endDecrypt(inst.allocator());
|
|
return mapCipherErr(e);
|
|
};
|
|
pulLastPartLen.* = @intCast(n);
|
|
sess.endDecrypt(inst.allocator());
|
|
return ck.CKR_OK;
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn C_DigestInit(hSession: ck.CK_SESSION_HANDLE, pMechanism: *ck.CK_MECHANISM) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.digest_op != null) return ck.CKR_OPERATION_ACTIVE;
|
|
sess.digest_op = digest.Hasher.init(pMechanism.mechanism) orelse return ck.CKR_MECHANISM_INVALID;
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_Digest(hSession: ck.CK_SESSION_HANDLE, pData: [*]ck.CK_BYTE, ulDataLen: ck.CK_ULONG, pDigest: ?[*]ck.CK_BYTE, pulDigestLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.digest_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const dlen: ck.CK_ULONG = @intCast(sess.digest_op.?.digestLen());
|
|
if (pDigest == null) {
|
|
pulDigestLen.* = dlen;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulDigestLen.* < dlen) {
|
|
pulDigestLen.* = dlen;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
sess.digest_op.?.update(part(pData, ulDataLen));
|
|
return emitDigest(sess, pDigest, pulDigestLen);
|
|
}
|
|
|
|
pub fn C_DigestUpdate(hSession: ck.CK_SESSION_HANDLE, pPart: [*]ck.CK_BYTE, ulPartLen: ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.digest_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
sess.digest_op.?.update(part(pPart, ulPartLen));
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_DigestKey(hSession: ck.CK_SESSION_HANDLE, hKey: ck.CK_OBJECT_HANDLE) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.digest_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const obj = inst.objects.getPtr(hKey) orelse return ck.CKR_KEY_HANDLE_INVALID;
|
|
if (!object_store.visible(obj, inst.logged_in)) return ck.CKR_KEY_HANDLE_INVALID;
|
|
if (objectClass(obj) != ck.CKO_SECRET_KEY) return ck.CKR_KEY_INDIGESTIBLE;
|
|
const sa = obj.findPtr(ck.CKA_VALUE) orelse return ck.CKR_KEY_INDIGESTIBLE;
|
|
if (sa.sealed) return ck.CKR_USER_NOT_LOGGED_IN;
|
|
sess.digest_op.?.update(sa.value);
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_DigestFinal(hSession: ck.CK_SESSION_HANDLE, pDigest: ?[*]ck.CK_BYTE, pulDigestLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.digest_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
return emitDigest(sess, pDigest, pulDigestLen);
|
|
}
|
|
|
|
pub fn C_SignInit(hSession: ck.CK_SESSION_HANDLE, pMechanism: *ck.CK_MECHANISM, hKey: ck.CK_OBJECT_HANDLE) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.sign_op != null) return ck.CKR_OPERATION_ACTIVE;
|
|
sess.sign_op = switch (signInitOp(inst, hKey, pMechanism)) {
|
|
.err => |rv| return rv,
|
|
.ok => |op| op,
|
|
};
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_Sign(hSession: ck.CK_SESSION_HANDLE, pData: [*]ck.CK_BYTE, ulDataLen: ck.CK_ULONG, pSignature: ?[*]ck.CK_BYTE, pulSignatureLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.sign_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const slen = signLen(&sess.sign_op.?);
|
|
if (pSignature == null) {
|
|
pulSignatureLen.* = slen;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulSignatureLen.* < slen) {
|
|
pulSignatureLen.* = slen;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
switch (sess.sign_op.?) {
|
|
.rsa => |op| {
|
|
const out = pSignature.?[0..@intCast(slen)];
|
|
const sc = switch (rsaPrivateComponents(inst, op.key, ck.CKA_SIGN)) {
|
|
.err => |rv| {
|
|
sess.endSign();
|
|
return rv;
|
|
},
|
|
.ok => |c| c,
|
|
};
|
|
const n = rsa.sign(sc, op.params, part(pData, ulDataLen), out) catch {
|
|
sess.endSign();
|
|
return ck.CKR_FUNCTION_FAILED;
|
|
};
|
|
pulSignatureLen.* = @intCast(n);
|
|
sess.endSign();
|
|
return ck.CKR_OK;
|
|
},
|
|
else => {
|
|
sess.sign_op.?.update(part(pData, ulDataLen));
|
|
return emitSign(inst, sess, pSignature, pulSignatureLen);
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn C_SignUpdate(hSession: ck.CK_SESSION_HANDLE, pPart: [*]ck.CK_BYTE, ulPartLen: ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.sign_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
switch (sess.sign_op.?) {
|
|
.rsa => return ck.CKR_FUNCTION_NOT_SUPPORTED,
|
|
else => {},
|
|
}
|
|
sess.sign_op.?.update(part(pPart, ulPartLen));
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_SignFinal(hSession: ck.CK_SESSION_HANDLE, pSignature: ?[*]ck.CK_BYTE, pulSignatureLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.sign_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
switch (sess.sign_op.?) {
|
|
.rsa => return ck.CKR_FUNCTION_NOT_SUPPORTED,
|
|
else => {},
|
|
}
|
|
return emitSign(inst, sess, pSignature, pulSignatureLen);
|
|
}
|
|
|
|
pub fn C_SignRecoverInit(hSession: ck.CK_SESSION_HANDLE, pMechanism: *ck.CK_MECHANISM, hKey: ck.CK_OBJECT_HANDLE) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.sign_recover_op != null) return ck.CKR_OPERATION_ACTIVE;
|
|
if (pMechanism.mechanism != ck.CKM_RSA_PKCS) return ck.CKR_MECHANISM_INVALID;
|
|
const pc = switch (rsaPrivateComponents(inst, hKey, ck.CKA_SIGN_RECOVER)) {
|
|
.err => |rv| return rv,
|
|
.ok => |c| c,
|
|
};
|
|
sess.sign_recover_op = .{ .key = hKey, .out_len = pc.n.len };
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_SignRecover(hSession: ck.CK_SESSION_HANDLE, pData: [*]ck.CK_BYTE, ulDataLen: ck.CK_ULONG, pSignature: ?[*]ck.CK_BYTE, pulSignatureLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
const op = if (sess.sign_recover_op) |o| o else return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const need: ck.CK_ULONG = @intCast(op.out_len);
|
|
if (pSignature == null) {
|
|
pulSignatureLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulSignatureLen.* < need) {
|
|
pulSignatureLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const in = part(pData, ulDataLen);
|
|
if (in.len + rsa.pkcs1_v15_min_overhead > op.out_len) {
|
|
sess.endSignRecover();
|
|
return ck.CKR_DATA_LEN_RANGE;
|
|
}
|
|
const sc = switch (rsaPrivateComponents(inst, op.key, ck.CKA_SIGN_RECOVER)) {
|
|
.err => |rv| {
|
|
sess.endSignRecover();
|
|
return rv;
|
|
},
|
|
.ok => |c| c,
|
|
};
|
|
const n = rsa.sign(sc, .{ .scheme = .pkcs1, .digest = .none }, in, pSignature.?[0..@intCast(need)]) catch {
|
|
sess.endSignRecover();
|
|
return ck.CKR_FUNCTION_FAILED;
|
|
};
|
|
pulSignatureLen.* = @intCast(n);
|
|
sess.endSignRecover();
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_VerifyInit(hSession: ck.CK_SESSION_HANDLE, pMechanism: *ck.CK_MECHANISM, hKey: ck.CK_OBJECT_HANDLE) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.verify_op != null) return ck.CKR_OPERATION_ACTIVE;
|
|
sess.verify_op = switch (verifyInitOp(inst, hKey, pMechanism)) {
|
|
.err => |rv| return rv,
|
|
.ok => |op| op,
|
|
};
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_Verify(hSession: ck.CK_SESSION_HANDLE, pData: [*]ck.CK_BYTE, ulDataLen: ck.CK_ULONG, pSignature: [*]ck.CK_BYTE, ulSignatureLen: ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.verify_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
switch (sess.verify_op.?) {
|
|
.rsa => |op| {
|
|
const data = part(pData, ulDataLen);
|
|
sess.endVerify();
|
|
if (ulSignatureLen != op.sig_len) return ck.CKR_SIGNATURE_LEN_RANGE;
|
|
const pc = switch (rsaPublicComponents(inst, op.key, ck.CKA_VERIFY)) {
|
|
.err => |rv| return rv,
|
|
.ok => |c| c,
|
|
};
|
|
const r = rsa.verify(pc, op.params, data, pSignature[0..@intCast(ulSignatureLen)]) catch return ck.CKR_FUNCTION_FAILED;
|
|
return switch (r) {
|
|
.ok => ck.CKR_OK,
|
|
.invalid => ck.CKR_SIGNATURE_INVALID,
|
|
};
|
|
},
|
|
else => {
|
|
sess.verify_op.?.update(part(pData, ulDataLen));
|
|
return finalizeVerify(sess, pSignature, ulSignatureLen);
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn C_VerifyUpdate(hSession: ck.CK_SESSION_HANDLE, pPart: [*]ck.CK_BYTE, ulPartLen: ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.verify_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
switch (sess.verify_op.?) {
|
|
.rsa => return ck.CKR_FUNCTION_NOT_SUPPORTED,
|
|
else => {},
|
|
}
|
|
sess.verify_op.?.update(part(pPart, ulPartLen));
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_VerifyFinal(hSession: ck.CK_SESSION_HANDLE, pSignature: [*]ck.CK_BYTE, ulSignatureLen: ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.verify_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
switch (sess.verify_op.?) {
|
|
.rsa => return ck.CKR_FUNCTION_NOT_SUPPORTED,
|
|
else => {},
|
|
}
|
|
return finalizeVerify(sess, pSignature, ulSignatureLen);
|
|
}
|
|
|
|
pub fn C_VerifyRecoverInit(hSession: ck.CK_SESSION_HANDLE, pMechanism: *ck.CK_MECHANISM, hKey: ck.CK_OBJECT_HANDLE) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.verify_recover_op != null) return ck.CKR_OPERATION_ACTIVE;
|
|
if (pMechanism.mechanism != ck.CKM_RSA_PKCS) return ck.CKR_MECHANISM_INVALID;
|
|
const pc = switch (rsaPublicComponents(inst, hKey, ck.CKA_VERIFY_RECOVER)) {
|
|
.err => |rv| return rv,
|
|
.ok => |c| c,
|
|
};
|
|
sess.verify_recover_op = .{ .key = hKey, .out_len = pc.n.len };
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_VerifyRecover(hSession: ck.CK_SESSION_HANDLE, pSignature: [*]ck.CK_BYTE, ulSignatureLen: ck.CK_ULONG, pData: ?[*]ck.CK_BYTE, pulDataLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
const op = if (sess.verify_recover_op) |o| o else return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
if (pData == null) {
|
|
pulDataLen.* = @intCast(op.out_len);
|
|
return ck.CKR_OK;
|
|
}
|
|
if (ulSignatureLen != op.out_len) {
|
|
sess.endVerifyRecover();
|
|
return ck.CKR_SIGNATURE_LEN_RANGE;
|
|
}
|
|
const pc = switch (rsaPublicComponents(inst, op.key, ck.CKA_VERIFY_RECOVER)) {
|
|
.err => |rv| {
|
|
sess.endVerifyRecover();
|
|
return rv;
|
|
},
|
|
.ok => |c| c,
|
|
};
|
|
var tmp: [rsa.max_modulus_bytes]u8 = undefined;
|
|
defer std.crypto.secureZero(u8, &tmp);
|
|
const m = rsa.recover(pc, part(pSignature, ulSignatureLen), &tmp) catch {
|
|
sess.endVerifyRecover();
|
|
return ck.CKR_SIGNATURE_INVALID;
|
|
};
|
|
if (pulDataLen.* < m) {
|
|
pulDataLen.* = @intCast(m);
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
@memcpy(pData.?[0..m], tmp[0..m]);
|
|
pulDataLen.* = @intCast(m);
|
|
sess.endVerifyRecover();
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_DigestEncryptUpdate(hSession: ck.CK_SESSION_HANDLE, pPart: [*]ck.CK_BYTE, ulPartLen: ck.CK_ULONG, pEncryptedPart: ?[*]ck.CK_BYTE, pulEncryptedPartLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.digest_op == null or sess.encrypt_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const op = &sess.encrypt_op.?;
|
|
const in = part(pPart, ulPartLen);
|
|
const need = switch (encUpdateNeed(op, in.len)) {
|
|
.err => |rv| return rv,
|
|
.ok => |n| n,
|
|
};
|
|
if (pEncryptedPart == null) {
|
|
pulEncryptedPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulEncryptedPartLen.* < need) {
|
|
pulEncryptedPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
sess.digest_op.?.update(in);
|
|
const wrote = switch (encUpdateEmit(inst, op, in, pEncryptedPart.?[0..@intCast(need)])) {
|
|
.err => |rv| {
|
|
sess.endEncrypt(inst.allocator());
|
|
return rv;
|
|
},
|
|
.ok => |n| n,
|
|
};
|
|
pulEncryptedPartLen.* = @intCast(wrote);
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_DecryptDigestUpdate(hSession: ck.CK_SESSION_HANDLE, pEncryptedPart: [*]ck.CK_BYTE, ulEncryptedPartLen: ck.CK_ULONG, pPart: ?[*]ck.CK_BYTE, pulPartLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.decrypt_op == null or sess.digest_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const op = &sess.decrypt_op.?;
|
|
if (!decryptSideDualOk(op)) return ck.CKR_FUNCTION_NOT_SUPPORTED;
|
|
const in = part(pEncryptedPart, ulEncryptedPartLen);
|
|
const need = switch (decUpdateNeed(op, in.len)) {
|
|
.err => |rv| return rv,
|
|
.ok => |n| n,
|
|
};
|
|
if (pPart == null) {
|
|
pulPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulPartLen.* < need) {
|
|
pulPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const out = pPart.?[0..@intCast(need)];
|
|
const wrote = switch (decUpdateEmit(inst, op, in, out)) {
|
|
.err => |rv| {
|
|
sess.endDecrypt(inst.allocator());
|
|
return rv;
|
|
},
|
|
.ok => |n| n,
|
|
};
|
|
sess.digest_op.?.update(out[0..wrote]);
|
|
pulPartLen.* = @intCast(wrote);
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_SignEncryptUpdate(hSession: ck.CK_SESSION_HANDLE, pPart: [*]ck.CK_BYTE, ulPartLen: ck.CK_ULONG, pEncryptedPart: ?[*]ck.CK_BYTE, pulEncryptedPartLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.sign_op == null or sess.encrypt_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
switch (sess.sign_op.?) {
|
|
.rsa => return ck.CKR_FUNCTION_NOT_SUPPORTED,
|
|
else => {},
|
|
}
|
|
const op = &sess.encrypt_op.?;
|
|
const in = part(pPart, ulPartLen);
|
|
const need = switch (encUpdateNeed(op, in.len)) {
|
|
.err => |rv| return rv,
|
|
.ok => |n| n,
|
|
};
|
|
if (pEncryptedPart == null) {
|
|
pulEncryptedPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulEncryptedPartLen.* < need) {
|
|
pulEncryptedPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
sess.sign_op.?.update(in);
|
|
const wrote = switch (encUpdateEmit(inst, op, in, pEncryptedPart.?[0..@intCast(need)])) {
|
|
.err => |rv| {
|
|
sess.endEncrypt(inst.allocator());
|
|
return rv;
|
|
},
|
|
.ok => |n| n,
|
|
};
|
|
pulEncryptedPartLen.* = @intCast(wrote);
|
|
return ck.CKR_OK;
|
|
}
|
|
|
|
pub fn C_DecryptVerifyUpdate(hSession: ck.CK_SESSION_HANDLE, pEncryptedPart: [*]ck.CK_BYTE, ulEncryptedPartLen: ck.CK_ULONG, pPart: ?[*]ck.CK_BYTE, pulPartLen: *ck.CK_ULONG) callconv(.c) ck.CK_RV {
|
|
const inst = state.acquire() orelse return ck.CKR_CRYPTOKI_NOT_INITIALIZED;
|
|
defer state.mutex.unlock();
|
|
const sess = inst.sessions.get(hSession) orelse return ck.CKR_SESSION_HANDLE_INVALID;
|
|
if (sess.decrypt_op == null or sess.verify_op == null) return ck.CKR_OPERATION_NOT_INITIALIZED;
|
|
const op = &sess.decrypt_op.?;
|
|
if (!decryptSideDualOk(op)) return ck.CKR_FUNCTION_NOT_SUPPORTED;
|
|
switch (sess.verify_op.?) {
|
|
.rsa => return ck.CKR_FUNCTION_NOT_SUPPORTED,
|
|
else => {},
|
|
}
|
|
const in = part(pEncryptedPart, ulEncryptedPartLen);
|
|
const need = switch (decUpdateNeed(op, in.len)) {
|
|
.err => |rv| return rv,
|
|
.ok => |n| n,
|
|
};
|
|
if (pPart == null) {
|
|
pulPartLen.* = need;
|
|
return ck.CKR_OK;
|
|
}
|
|
if (pulPartLen.* < need) {
|
|
pulPartLen.* = need;
|
|
return ck.CKR_BUFFER_TOO_SMALL;
|
|
}
|
|
const out = pPart.?[0..@intCast(need)];
|
|
const wrote = switch (decUpdateEmit(inst, op, in, out)) {
|
|
.err => |rv| {
|
|
sess.endDecrypt(inst.allocator());
|
|
return rv;
|
|
},
|
|
.ok => |n| n,
|
|
};
|
|
sess.verify_op.?.update(out[0..wrote]);
|
|
pulPartLen.* = @intCast(wrote);
|
|
return ck.CKR_OK;
|
|
}
|