pkgbootrl.c 5.07 KB
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <bbtoolsapi.h>
#include <PR/bbskapi.h>

void usage()
{
    fprintf(stderr, 
            "Usage: pkgbootrl [-c cert.sys] [-r crl.sys] [cmdhfile]\n"
            "    If cmdhfile is present, it is input, then overwritten on\n"
            "    output. If omitted, stdin is used for input and stdout is\n"
            "    used for output.\n");
}


u8 *fReadStream(FILE *fp)
{
    struct stat fStat;
    u8 *buf;

    buf=malloc(16384);
    fread(buf,1,16384,fp);
    return buf;
}

u8 *fRead(const char *fname)
{
    FILE *fp;
    struct stat fStat;
    u8 *buf;

    if ((fp= fopen(fname, "r")) == NULL) {
        return 0;
    }
    fstat(fileno(fp),&fStat);
    buf=malloc(fStat.st_size);
    fread(buf,1,fStat.st_size,fp);
    fclose(fp);
    return buf;
}

#define EXIT ret=1; goto cleanup

int main(int argc, char* argv[])
{
    FILE* fp=NULL;
    u8 *certs=NULL, *rls=NULL, *cmdBundleIn=NULL;
    int ret=0, numCerts=0, numRls=0, useStdio=0;
    BbAppLaunchCrls launchRls;
    BbRsaCert *cpca=NULL;
    BbCrlHead *rl, *carl=NULL, *cprl=NULL;
    int i,carlsize=0,cprlsize=0;
    int cmdBundleInSize=sizeof(BbContentMetaDataHead)+sizeof(BbRsaCert)*2;
    char c;

    bzero(&launchRls, sizeof launchRls);

    while ((c = getopt(argc, argv, "c:r:h")) != EOF) {
        switch (c) {
	case 'c':
            if((certs = fRead(optarg)) == NULL){
                perror(optarg);
                EXIT;
            }            
            numCerts = ntohl(*(u32 *)certs);
            break;
	case 'r':
            if((rls = fRead(optarg)) == NULL){
                perror(optarg);
                EXIT;
            }            
            numRls = ntohl(*(u32 *)rls);
            break;
        case 'h':
        default:
            usage();
            EXIT;
        }
    }

    if((argc-optind)>1){
        perror("\ntoo many args (1 max)\n\n");
        usage();
        EXIT;
    }

    if(argc==optind){
        useStdio = 1;
    }

    if(useStdio){
        if((cmdBundleIn = fReadStream(stdin)) == NULL){
            perror("can't read stdin");
            EXIT;
        }
    }
    else if((cmdBundleIn = fRead(argv[optind])) == NULL){
        perror(argv[optind]);
        EXIT;
    }
    
    rl=(BbCrlHead *)(rls+4);
    for(i=0 ; i<numRls; i++){
        if(ntohl(rl->type) == BB_CRL_TYPE_CA){
            carl = rl;
            launchRls.carl.head = (void *)htonl((cmdBundleInSize + 
                                           (sizeof launchRls)));
            launchRls.carl.list = 
                (void *)htonl((ntohl((int)launchRls.carl.head) + 
                               sizeof(BbCrlHead)));
            carlsize = sizeof(BbCrlHead) +
                ntohl(carl->numberRevoked)*sizeof(BbCrlEntry);
        }
        else if(ntohl(rl->type) == BB_CRL_TYPE_CP){
            cprl = rl;
            /* cprl could require one extra cert to be added (CPCA) */
            cpca = (BbRsaCert *)(cmdBundleIn+sizeof(BbContentMetaDataHead)
                                 +sizeof(BbRsaCert));
            if(strcmp(cpca->certId.name.server,&(cprl->issuer[5]))){
                /* need extra cpca cert from cert.sys */
                for(i=0, cpca=(BbRsaCert *)(certs+4);
                    i<numCerts && strcmp(cpca->certId.name.server,
                                          &(cprl->issuer[5]));
                    i++, cpca++){}
                if(i==numCerts){
                    perror("cannot find signer cert for carl\n");
                    EXIT;
                }
            }
            else
                cpca=NULL;
            
            /* fix ptrs */
            launchRls.cprl.head = (void *)htonl((cmdBundleInSize + 
                                           (sizeof launchRls) + carlsize));
            launchRls.cprl.list = 
                (void *)htonl((ntohl((int)launchRls.cprl.head) + 
                               sizeof(BbCrlHead)));
            launchRls.cprl.certChain[0] = (void *)htonl((cmdBundleInSize - 
                                                   sizeof(BbRsaCert)));
            cprlsize = sizeof(BbCrlHead) +
                ntohl(cprl->numberRevoked)*sizeof(BbCrlEntry);
            if(cpca)
                launchRls.cprl.certChain[0] = 
                    (void *)htonl((ntohl((int)launchRls.cprl.head) + 
                                   cprlsize));
        }
    }
    

    /* output bundle */
    if(useStdio){
        fp = stdout;
    }
    else if((fp = fopen(argv[optind], "w")) == NULL) {
        EXIT;
    }
    if(fwrite(cmdBundleIn,1,cmdBundleInSize,fp) < 0){
        EXIT;
    }
    if(fwrite(&launchRls,1,sizeof launchRls,fp) < 0){
        EXIT;
    }
    if(carl && (fwrite(carl,1,carlsize,fp) < 0)){
        EXIT;
    }
    if(cprl && (fwrite(cprl,1,cprlsize,fp) < 0)){
        EXIT;
    }
    if(cpca && (fwrite(cpca,1,sizeof(BbRsaCert),fp) < 0)){
        EXIT;
    }

 cleanup:
    if(certs) free(certs);
    if(carl) free(rls);
    if(cmdBundleIn) free(cmdBundleIn);
    if(!useStdio && fp) fclose(fp);
    return ret;
}