structstd.crypto.Certificate.rsa.PSSSignature[src]

RFC 3447 8.1 RSASSA-PSS

Error Sets

Error SetVerifyError[src]

Errors

anyerror means the error set is known only at runtime.

InvalidSignature
MessageTooLong EncryptError

Source Code

Source code
pub const VerifyError = EncryptError || error{InvalidSignature}

Functions

FunctionfromBytes[src]

pub fn fromBytes(comptime modulus_len: usize, msg: []const u8) [modulus_len]u8

Parameters

modulus_len: usize
msg: []const u8

Source Code

Source code
pub fn fromBytes(comptime modulus_len: usize, msg: []const u8) [modulus_len]u8 {
    var result: [modulus_len]u8 = undefined;
    @memcpy(result[0..msg.len], msg);
    @memset(result[msg.len..], 0);
    return result;
}

Functionverify[src]

pub fn verify( comptime modulus_len: usize, sig: [modulus_len]u8, msg: []const u8, public_key: PublicKey, comptime Hash: type, ) VerifyError!void

Parameters

modulus_len: usize
sig: [modulus_len]u8
msg: []const u8
public_key: PublicKey
Hash: type

Source Code

Source code
pub fn verify(
    comptime modulus_len: usize,
    sig: [modulus_len]u8,
    msg: []const u8,
    public_key: PublicKey,
    comptime Hash: type,
) VerifyError!void {
    try concatVerify(modulus_len, sig, &.{msg}, public_key, Hash);
}

FunctionconcatVerify[src]

pub fn concatVerify( comptime modulus_len: usize, sig: [modulus_len]u8, msg: []const []const u8, public_key: PublicKey, comptime Hash: type, ) VerifyError!void

Parameters

modulus_len: usize
sig: [modulus_len]u8
msg: []const []const u8
public_key: PublicKey
Hash: type

Source Code

Source code
pub fn concatVerify(
    comptime modulus_len: usize,
    sig: [modulus_len]u8,
    msg: []const []const u8,
    public_key: PublicKey,
    comptime Hash: type,
) VerifyError!void {
    const mod_bits = public_key.n.bits();
    const em_dec = try encrypt(modulus_len, sig, public_key);

    try EMSA_PSS_VERIFY(msg, &em_dec, mod_bits - 1, Hash.digest_length, Hash);
}

Source Code

Source code
pub const PSSSignature = struct {
    pub fn fromBytes(comptime modulus_len: usize, msg: []const u8) [modulus_len]u8 {
        var result: [modulus_len]u8 = undefined;
        @memcpy(result[0..msg.len], msg);
        @memset(result[msg.len..], 0);
        return result;
    }

    pub const VerifyError = EncryptError || error{InvalidSignature};

    pub fn verify(
        comptime modulus_len: usize,
        sig: [modulus_len]u8,
        msg: []const u8,
        public_key: PublicKey,
        comptime Hash: type,
    ) VerifyError!void {
        try concatVerify(modulus_len, sig, &.{msg}, public_key, Hash);
    }

    pub fn concatVerify(
        comptime modulus_len: usize,
        sig: [modulus_len]u8,
        msg: []const []const u8,
        public_key: PublicKey,
        comptime Hash: type,
    ) VerifyError!void {
        const mod_bits = public_key.n.bits();
        const em_dec = try encrypt(modulus_len, sig, public_key);

        try EMSA_PSS_VERIFY(msg, &em_dec, mod_bits - 1, Hash.digest_length, Hash);
    }

    fn EMSA_PSS_VERIFY(msg: []const []const u8, em: []const u8, emBit: usize, sLen: usize, comptime Hash: type) VerifyError!void {
        // 1.   If the length of M is greater than the input limitation for
        //      the hash function (2^61 - 1 octets for SHA-1), output
        //      "inconsistent" and stop.
        // All the cryptographic hash functions in the standard library have a limit of >= 2^61 - 1.
        // Even then, this check is only there for paranoia. In the context of TLS certificates, emBit cannot exceed 4096.
        if (emBit >= 1 << 61) return error.InvalidSignature;

        // emLen = \ceil(emBits/8)
        const emLen = ((emBit - 1) / 8) + 1;
        std.debug.assert(emLen == em.len);

        // 2.   Let mHash = Hash(M), an octet string of length hLen.
        var mHash: [Hash.digest_length]u8 = undefined;
        {
            var hasher: Hash = .init(.{});
            for (msg) |part| hasher.update(part);
            hasher.final(&mHash);
        }

        // 3.   If emLen < hLen + sLen + 2, output "inconsistent" and stop.
        if (emLen < Hash.digest_length + sLen + 2) {
            return error.InvalidSignature;
        }

        // 4.   If the rightmost octet of EM does not have hexadecimal value
        //      0xbc, output "inconsistent" and stop.
        if (em[em.len - 1] != 0xbc) {
            return error.InvalidSignature;
        }

        // 5.   Let maskedDB be the leftmost emLen - hLen - 1 octets of EM,
        //      and let H be the next hLen octets.
        const maskedDB = em[0..(emLen - Hash.digest_length - 1)];
        const h = em[(emLen - Hash.digest_length - 1)..(emLen - 1)][0..Hash.digest_length];

        // 6.   If the leftmost 8emLen - emBits bits of the leftmost octet in
        //      maskedDB are not all equal to zero, output "inconsistent" and
        //      stop.
        const zero_bits = emLen * 8 - emBit;
        var mask: u8 = maskedDB[0];
        var i: usize = 0;
        while (i < 8 - zero_bits) : (i += 1) {
            mask = mask >> 1;
        }
        if (mask != 0) {
            return error.InvalidSignature;
        }

        // 7.   Let dbMask = MGF(H, emLen - hLen - 1).
        const mgf_len = emLen - Hash.digest_length - 1;
        var mgf_out_buf: [512]u8 = undefined;
        if (mgf_len > mgf_out_buf.len) { // Modulus > 4096 bits
            return error.InvalidSignature;
        }
        const mgf_out = mgf_out_buf[0 .. ((mgf_len - 1) / Hash.digest_length + 1) * Hash.digest_length];
        var dbMask = try MGF1(Hash, mgf_out, h, mgf_len);

        // 8.   Let DB = maskedDB \xor dbMask.
        i = 0;
        while (i < dbMask.len) : (i += 1) {
            dbMask[i] = maskedDB[i] ^ dbMask[i];
        }

        // 9.   Set the leftmost 8emLen - emBits bits of the leftmost octet
        //      in DB to zero.
        i = 0;
        mask = 0;
        while (i < 8 - zero_bits) : (i += 1) {
            mask = mask << 1;
            mask += 1;
        }
        dbMask[0] = dbMask[0] & mask;

        // 10.  If the emLen - hLen - sLen - 2 leftmost octets of DB are not
        //      zero or if the octet at position emLen - hLen - sLen - 1 (the
        //      leftmost position is "position 1") does not have hexadecimal
        //      value 0x01, output "inconsistent" and stop.
        if (dbMask[mgf_len - sLen - 2] != 0x00) {
            return error.InvalidSignature;
        }

        if (dbMask[mgf_len - sLen - 1] != 0x01) {
            return error.InvalidSignature;
        }

        // 11.  Let salt be the last sLen octets of DB.
        const salt = dbMask[(mgf_len - sLen)..];

        // 12.  Let
        //         M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
        //      M' is an octet string of length 8 + hLen + sLen with eight
        //      initial zero octets.
        if (sLen > Hash.digest_length) { // A seed larger than the hash length would be useless
            return error.InvalidSignature;
        }
        var m_p_buf: [8 + Hash.digest_length + Hash.digest_length]u8 = undefined;
        var m_p = m_p_buf[0 .. 8 + Hash.digest_length + sLen];
        std.mem.copyForwards(u8, m_p, &([_]u8{0} ** 8));
        std.mem.copyForwards(u8, m_p[8..], &mHash);
        std.mem.copyForwards(u8, m_p[(8 + Hash.digest_length)..], salt);

        // 13.  Let H' = Hash(M'), an octet string of length hLen.
        var h_p: [Hash.digest_length]u8 = undefined;
        Hash.hash(m_p, &h_p, .{});

        // 14.  If H = H', output "consistent".  Otherwise, output
        //      "inconsistent".
        if (!std.mem.eql(u8, h, &h_p)) {
            return error.InvalidSignature;
        }
    }

    fn MGF1(comptime Hash: type, out: []u8, seed: *const [Hash.digest_length]u8, len: usize) ![]u8 {
        var counter: u32 = 0;
        var idx: usize = 0;
        var hash = seed.* ++ @as([4]u8, undefined);

        while (idx < len) {
            std.mem.writeInt(u32, hash[seed.len..][0..4], counter, .big);
            Hash.hash(&hash, out[idx..][0..Hash.digest_length], .{});
            idx += Hash.digest_length;
            counter += 1;
        }

        return out[0..len];
    }
}