sign.c 7.62 KB
#include <string.h>
#include <PR/bbskapi.h>
#include <sha1.h>

#include "os.h"
#include "os_bb.h"
#include "bbint.h"

typedef struct {
    char name[BB_INODE16_NAMELEN];
    BbEccSig sig;
} sig_entry_t;

#define SIG_DB "sig.db"

void __osBbFsUnformatName(const char *fname, char *name)
{
    int f, n;
    char ptr[BB_INODE16_NAMELEN];

    f = n = 0;
    bcopy(fname, ptr, BB_INODE16_NAMELEN);
    *ptr &= 0x7F;
    while (f < BB_INODE16_NAMELEN-3 && ptr[f]) {
        name[n++] = ptr[f++];
    }
    f = BB_INODE16_NAMELEN-3;
    if (ptr[f]) {
        name[n++] = '.';
        while (f < BB_INODE16_NAMELEN && ptr[f]) {
            name[n++] = ptr[f++];
        }
    }
    name[n] = '\0';
}

int __osBbSigNameCmp(const void *name1, const void *name2) 
{
    int len = BB_INODE16_NAMELEN;
    char ptr1[BB_INODE16_NAMELEN];
    char ptr2[BB_INODE16_NAMELEN];

    bcopy(name1, ptr1, BB_INODE16_NAMELEN);
    bcopy(name2, ptr2, BB_INODE16_NAMELEN);
    *ptr1 |= 0x80;
    *ptr2 |= 0x80;

    return bcmp(ptr1, ptr2, len);
}

/* quick and dirty way of checking dirty state:
 * 0:  clean state
 * 1:  dirty state
 * -1: sig not found
 */
int __osBbIsSigDirty(const char *name, u8 block[BB_FL_BLOCK_SIZE])
{
    s32 fd = -1;
    sig_entry_t *s = (sig_entry_t *)block;
    char fname[BB_INODE16_NAMELEN];

    __osBbFsFormatName(fname, name);
    if ((fd = osBbFOpen(SIG_DB, "r")) < 0) {
        goto error;
    }

    if (osBbFRead(fd, 0, block, BB_FL_BLOCK_SIZE) < 0) {
        goto error;
    }

    while (s < (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
        if (!s->name[0])
            break;

        if (!bcmp(s->name, fname, BB_INODE16_NAMELEN)) {
            if (fd >= 0) osBbFClose(fd);
            return 0;
        } else if (!__osBbSigNameCmp(s->name, fname)) {
            if (fd >= 0) osBbFClose(fd);
            return 1;
        }

        ++s;
    }

error:
    if (fd >= 0) osBbFClose(fd);
    return -1;
}

s32 __osBbInsertSig(const char *name, BbEccSig sig, u8 block[BB_FL_BLOCK_SIZE])
{
    s32 fd = -1;
    sig_entry_t *s = (sig_entry_t *)block;
    char fname[BB_INODE16_NAMELEN];

    __osBbFsFormatName(fname, name);
    if ((fd = osBbFOpen(SIG_DB, "r+")) < 0) {
        if (fd == BBFS_ERR_ENTRY) {
            if ((fd = osBbFCreate(SIG_DB, 1, BB_FL_BLOCK_SIZE)) < 0) {
                goto error;
            }
            bzero(block, BB_FL_BLOCK_SIZE);
            if (osBbFWrite(fd, 0, block, BB_FL_BLOCK_SIZE) < 0) {
                goto error;
            }
        } else {
            goto error;
        }
    }

    if (osBbFRead(fd, 0, block, BB_FL_BLOCK_SIZE) < 0) {
        goto error;
    }

    /* Look for existing entry */
    while (s < (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
        if (!__osBbSigNameCmp(s->name, fname))
            break;

        ++s;
    }

    /* If doesn't exist, look for empty entry */
    if (s >= (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
        while (s < (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
            if (!s->name[0])
                break;

            ++s;
        }
    }

    /* If no existing or empty entry, then garbage collect one */
    if (s >= (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
        s = (sig_entry_t *)block;
        while (s < (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
            char uname[BB_INODE16_NAMELEN+2];
            s32 efd;
            __osBbFsUnformatName(s->name, uname);
            if ((efd = osBbFOpen(uname, "r")) < 0) {
                break;
            }
            osBbFClose(efd);
            ++s;

        }
    }

    /* If entry found, then write signature, otherwise it is an error */
    if (s < (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
        bcopy(fname, s->name, BB_INODE16_NAMELEN);
        bcopy(sig, s->sig, sizeof(s->sig));
        if (osBbFWrite(fd, 0, block, BB_FL_BLOCK_SIZE) < 0) {
            goto error;
        }
    } else {
        goto error;
    }

    if (fd >= 0) osBbFClose(fd);
    return 0;

error:
    if (fd >= 0) osBbFClose(fd);
    return -1;
}

s32 __osBbLookupSig(const char *name, BbEccSig sig, u8 block[BB_FL_BLOCK_SIZE])
{
    s32 fd = -1;
    sig_entry_t *s = (sig_entry_t *)block;
    char fname[BB_INODE16_NAMELEN];

    __osBbFsFormatName(fname, name);
    if ((fd = osBbFOpen(SIG_DB, "r")) < 0) {
        goto error;
    }

    if (osBbFRead(fd, 0, block, BB_FL_BLOCK_SIZE) < 0) {
        goto error;
    }

    while (s < (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
        if (!s->name[0])
            break;

        if (!__osBbSigNameCmp(s->name, fname)) {
            bcopy(s->sig, sig, sizeof(BbEccSig));
            if (fd >= 0) osBbFClose(fd);
            return 0;
        }

        ++s;
    }

error:
    if (fd >= 0) osBbFClose(fd);
    return -1;
}

s32 __osBbDeleteSig(const char *name, u8 block[BB_FL_BLOCK_SIZE])
{
    s32 fd = -1;
    sig_entry_t *s = (sig_entry_t *)block;
    char fname[BB_INODE16_NAMELEN];

    __osBbFsFormatName(fname, name);
    if ((fd = osBbFOpen(SIG_DB, "r+")) < 0) {
        if (fd == BBFS_ERR_ENTRY) {
            return 0;
        } else {
            goto error;
        }
    }

    if (osBbFRead(fd, 0, block, BB_FL_BLOCK_SIZE) < 0) {
        goto error;
    }

    while (s < (sig_entry_t *)(block+BB_FL_BLOCK_SIZE-sizeof(sig_entry_t))) {
        if (!s->name[0] ||
            !__osBbSigNameCmp(s->name, fname)) {
            bcopy(s+1, s, BB_FL_BLOCK_SIZE-((u8*)(s+1)-block));
            if (osBbFWrite(fd, 0, block, BB_FL_BLOCK_SIZE) < 0) {
                goto error;
            }
            break;
        }
        ++s;
    }

    if (fd >= 0) osBbFClose(fd);
    return 0;

error:
    if (fd >= 0) osBbFClose(fd);
    return -1;
}

s32 __osBbHashFile(const char *name, BbShaHash hash, u8 block[BB_FL_BLOCK_SIZE])
{
    s32 fd = -1;
    SHA1Context sha;
    OSBbStatBuf sb;
    u32 i;

    if ((fd = osBbFOpen(name, "r")) < 0) {
        goto error;
    }

    if (osBbFStat(fd, &sb, NULL, 0) < 0) {
        goto error;
    }

    SHA1Reset(&sha);
    for (i = 0; i < sb.size; i+=BB_FL_BLOCK_SIZE) {
        if (osBbFRead(fd, i, block, BB_FL_BLOCK_SIZE) < 0) {
            goto error;
        }
        SHA1Input(&sha, block, BB_FL_BLOCK_SIZE);
    }
    SHA1Result(&sha, (u8*)hash);
    if (fd >= 0) osBbFClose(fd);
    return 0;

error:
    if (fd >= 0) osBbFClose(fd);
    return -1;
}

u32 __osBbNoSk = 0;
s32 osBbSignFile(const char *name, u8 block[BB_FL_BLOCK_SIZE])
{
    BbShaHash hash;
    BbEccSig sig;

    if (__osBbNoSk)
        return 0;

    if (__osBbHashFile(name, hash, block) < 0) {
        goto error;
    }

    if (skSignHash(hash, sig) != SK_API_SUCCESS) {
        goto error;
    }

    if (__osBbInsertSig(name, sig, block) < 0) {
        goto error;
    }

    return 0;
error:
    return -1;
}

s32 osBbVerifyFile(const char *name, u8 block[BB_FL_BLOCK_SIZE])
{
    BbShaHash hash;
    BbEccSig sig;

    if (__osBbNoSk)
        return 1;

    if ((__osBbLookupSig(name, sig, block) < 0) ||
        (__osBbHashFile(name, hash, block) < 0)) {
        goto error;
    }

    return (skVerifyHash(hash, (BbGenericSig *)sig, 0, 0) == SK_API_SUCCESS);

error:
    return 0;
}

s32 osBbVerifySig(const char *name, BbEccSig sig, u8 block[BB_FL_BLOCK_SIZE])
{
    BbShaHash hash;

    if (__osBbNoSk)
        return 1;

    if (__osBbHashFile(name, hash, block) < 0) {
        goto error;
    }

    return (skVerifyHash(hash, (BbGenericSig *)sig, 0, 0) == SK_API_SUCCESS);

error:
    return 0;
}

s32 osBbDeleteSignedFile(const char *name, u8 block[BB_FL_BLOCK_SIZE])
{
    s32 rv;

    if ((rv = __osBbDeleteSig(name, block)) < 0)
        return rv;

    return osBbFDelete(name);
}