rl.c 10.6 KB
#include <PR/bcp.h>
#include <PR/bbboot.h>
#include <PR/bbnand.h>
#include <PR/bbticket.h>
#include <PR/bbvirage.h>
#include <PR/bbcert.h>
#include <PR/bbskapi.h>
#include "util.h"
#include "skerror.h"
#include "cert.h"
#include "rl.h"

extern BbRsaPublicKey4096 gRootKey;
extern BbRsaExponent      gRootExp;

int getInternalRlVersion(u32 rlType, u32 *version)
{
    switch(rlType){
    case BB_CRL_TYPE_XS:
        *version = v01.tsCrlVersion;
        return SK_SUCCESS;
    case BB_CRL_TYPE_CP:
        *version = v01.cpCrlVersion;
        return SK_SUCCESS;
    case BB_CRL_TYPE_CA:
        *version = v01.caCrlVersion;
        return SK_SUCCESS;
    }
    
    return SK_FAIL;
}

int consistentRlNaming(BbCrlHead *head,u32 rlType)
{
    if(head->type != rlType)
        return SK_FAIL;

    switch(rlType){
    case BB_CRL_TYPE_XS:
        if(strncmp(head->issuer,BB_CERT_STR_XSCA_CHAIN,9))
            return SK_FAIL;
        break;
    case BB_CRL_TYPE_CP:
        if(strncmp(head->issuer,BB_CERT_STR_CPCA_CHAIN,9))
            return SK_FAIL;
        break;
    case BB_CRL_TYPE_CA:
        if(strncmp(head->issuer,BB_CERT_STR_ROOT,5))
            return SK_FAIL;
        break;
    default:
        return SK_FAIL;
    }
    
    return SK_SUCCESS;
}

int updateRl(BbCrlBundle *rl)
{
    switch(rl->head->type){
    case BB_CRL_TYPE_XS:
        if(rl->head->versionNumber > (u32)v01.tsCrlVersion)
            v01.tsCrlVersion = (u8)rl->head->versionNumber;
        else
            return SK_SUCCESS;
        break;
    case BB_CRL_TYPE_CP:
        if(rl->head->versionNumber > (u32)v01.cpCrlVersion)
            v01.cpCrlVersion = (u8)rl->head->versionNumber;
        else
            return SK_SUCCESS;
        break;
    case BB_CRL_TYPE_CA:
        if(rl->head->versionNumber > (u32)v01.caCrlVersion){
            v01.caCrlVersion = (u8)rl->head->versionNumber;
            /* and all others go to zero */
            v01.cpCrlVersion = 0;
            v01.contentRlVersion = 0;
            v01.tsCrlVersion = 0;
        }
        else
            return SK_SUCCESS;
        break;
    default:
        /* can't really get here since type hardcoded in rl.c earlier
         * in callstack. leaving to catch coding bug of wrong type.
         */
        return SK_FAIL;
    }

    if(v01Update(&v01) != SK_SUCCESS){
        message("updateRl(): v01Update Fail.\n");
        return SK_FAIL;
    }

    return SK_SUCCESS;
}


/* it would be nice to only obtain the rl type from the rl arg,
 * but we could get spoofed when interpretting versionNumber==0
 * as having no rl for this type (by the sysapp providing the
 * wrong type, leading to another lists v012Version coming back
 * for comparison).
 */
int validateRl(BbCrlBundle *rl, u32 rlType, u32 ticketVersion)
{
    u32 v01Version;
    SkDataChain dataChain[2];
    u32 chainType = CHAIN_TYPE_DONT_CARE;
    int ret;

    if(getInternalRlVersion(rlType,&v01Version)!=SK_SUCCESS){
        /* should never fail since rlType hard-coded in calls to
         * validateRl. leaving just to catch coding errors.
         */
        return SK_FAIL;
    }
    
    if(rl->head==0){
        if(v01Version==0){
            /* a NULL head implies nothing revoked. OK as long as internal
             * version is 0. 
             */
            if(ticketVersion>0){
                /* no internal counter update since ticket not verified.
                 * do not want bogus ticket to prevent future sysapp launch!
                 */
                return SK_FAIL;
            }
            return SK_SUCCESS;
        }
        else{
            return SK_FAIL;
        }
    }

    if(v01Version > rl->head->versionNumber
       || ticketVersion > rl->head->versionNumber){
        /* no internal counter update for ticketVersion clause since 
         * ticket not verified
         */
        return SK_FAIL;
    }

    if(consistentRlNaming(rl->head,rlType) != SK_SUCCESS){
        return SK_FAIL;
    }

    /* verify chain, but no chain for carl since root signed */
    if(rlType != BB_CRL_TYPE_CA){
        switch(rlType){
        case BB_CRL_TYPE_XS:
            chainType = CHAIN_TYPE_TICKET_PUB;
            break;
        case BB_CRL_TYPE_CP:
            chainType = CHAIN_TYPE_CONTENT_PUB;
            break;
        default:
            return SK_FAIL;
        }        
        if(verifyCertChain(rl->certChain, chainType) != SK_SUCCESS){
            return SK_FAIL;
        }
    }

    /* check signature */
    dataChain[0].data = (u8 *)(rl->head)+sizeof(rl->head->signature);
    dataChain[0].size = sizeof(BbCrlHead) - sizeof(rl->head->signature);
    dataChain[1].data = (u8 *)rl->list;
    dataChain[1].size = rl->head->numberRevoked * sizeof(BbCrlEntry);
    if(strcmp(rl->head->issuer,BB_CERT_STR_ROOT) == 0) {
        ret = verifyRsaSigDataChain(dataChain,2,(u32 *)gRootKey,gRootExp,
                            BB_SIG_TYPE_RSA4096, &(rl->head->signature));
    }
    else{
        ret = verifyRsaSigDataChain(dataChain, 2,
                     (u32 *)(((BbRsaCert *)(rl->certChain[0]))->publicKey),
                                ((BbRsaCert *)(rl->certChain[0]))->exponent,
                            rl->head->sigType,
                                &(rl->head->signature));
    }

    if(ret!=SK_SUCCESS)
        return ret;

    return updateRl(rl);
}

/* if tsrlVersion is -1, ignore tsrl */
int validateRls(BbCrlBundle *carl, int carlVersion, 
              BbCrlBundle *cprl, int cprlVersion,
              BbCrlBundle *tsrl, int tsrlVersion)
{
    int i;

    /* NOTE: only want to update v01 for valid RL. since validation
     *       dependencies exist (i.e., tsrl, cprl and crl depend on 
     *       carl), and since the occurence of v01 rl updates must be low
     *       (we only have 8 bits for version), easiest to v01 update one
     *       rl at a time as we go. the update occurs in validateRl().
     */

    /* is CARL valid? */
    if(validateRl(carl, BB_CRL_TYPE_CA, carlVersion) != SK_SUCCESS)
        return SK_API_INVALID_CARL;

    /* for all CARL entries, are there any certs in chains for:
     *   - cprl
     *   - tsrl
     *  if so, FAIL.
     */
    if(RL_EXISTS(*carl)){
        for(i=0; i<carl->head->numberRevoked; i++){
            if(strstr(cprl->certChain[0]->name.server, carl->list[i])!=NULL)
                return SK_API_REVOKED_SERVER;
            if(tsrlVersion >= 0 &&
               strstr(tsrl->certChain[0]->name.server, carl->list[i])!=NULL)
                return SK_API_REVOKED_SERVER;
        }
    }
        
    /* is CPRL valid? */
    if(validateRl(cprl, BB_CRL_TYPE_CP, cprlVersion) != SK_SUCCESS)
        return SK_API_INVALID_CPRL;

    /* is TSRL valid? */
    if(tsrlVersion>=0 && (validateRl(tsrl, BB_CRL_TYPE_XS, tsrlVersion) 
                        != SK_SUCCESS))
        return SK_API_INVALID_TSRL;

    return SK_SUCCESS;
}


/*
 * return SK_API failure codes if revoked. otherwise SK_SUCCESS.
 */
int ticketBundleRevoked(BbTicketBundle *ticketBundle, 
                        BbAppLaunchCrls *crls)
{
    int ret,i;

    if(!rlPtrsValid(crls))
        return SK_API_FAIL;

    /* first check the rls themselves (will update v01 as needed) */
    ret = validateRls(&crls->carl,ticketBundle->ticket->cmd.head.caCrlVersion,
                      &crls->cprl,ticketBundle->ticket->cmd.head.cpCrlVersion,
                      &crls->tsrl,ticketBundle->ticket->head.tsCrlVersion);

    if(ret != SK_SUCCESS)
        return ret;

    /* now check the ticket and cmd chains */
    if(RL_EXISTS(crls->carl)){
        for(i=0; i<crls->carl.head->numberRevoked; i++){
            if(strstr(ticketBundle->ticketChain[1]->name.server,
                      crls->carl.list[i])!=NULL)
                return SK_API_REVOKED_SERVER;
            if(strstr(ticketBundle->cmdChain[1]->name.server,
                      crls->carl.list[i])!=NULL)
                return SK_API_REVOKED_SERVER;
        }
    }
    if(RL_EXISTS(crls->cprl)){
        for(i=0; i<crls->cprl.head->numberRevoked; i++){
            if(strstr(ticketBundle->cmdChain[0]->name.server,
                      crls->cprl.list[i])!=NULL)
                return SK_API_REVOKED_SERVER;
        }
    }
    if(RL_EXISTS(crls->tsrl)){
        for(i=0; i<crls->tsrl.head->numberRevoked; i++){
            if(strstr(ticketBundle->ticketChain[0]->name.server,
                      crls->tsrl.list[i])!=NULL)
                return SK_API_REVOKED_SERVER;
        }
    }

    return SK_API_SUCCESS;
}


/* NOTE: don't use crls->tsrl here. */
int sysappBundleRevoked(BbContentMetaDataHead *cmdh,
                        BbCertBase **cmdChain,
                        BbAppLaunchCrls *crls)
{
    int i, ret;

    /* check the rl bundle ptrs here in sysapp case */
    if(RL_EXISTS(crls->carl)){
        if(!bundlePtrValid(crls->carl.head, sizeof *crls->carl.head, 4))
            return SK_FAIL;
        if(!bundlePtrValid(crls->carl.list, 
                    sizeof(BbCrlEntry)*crls->carl.head->numberRevoked, 4))
            return SK_FAIL;
    }
    if(RL_EXISTS(crls->cprl)){
        if(!bundlePtrValid(crls->cprl.head, sizeof *crls->cprl.head, 4))
            return SK_FAIL;
        if(!bundlePtrValid(crls->cprl.list, 
                    sizeof(BbCrlEntry)*crls->cprl.head->numberRevoked, 4))
            return SK_FAIL;
        if(!bundlePtrValid(crls->cprl.certChain,4,4))
            return SK_FAIL;
        if(!bundlePtrValid(crls->cprl.certChain[0],sizeof(BbRsaCert),4))
            return SK_FAIL;
    }

    /* first check the rls themselves (will update v01 as needed) */
    ret = validateRls(&crls->carl, cmdh->caCrlVersion, 
                      &crls->cprl, cmdh->cpCrlVersion,
                      &crls->tsrl, -1);

    if(ret != SK_SUCCESS)
        return ret;

    /* now check the cmd chains */

    if(RL_EXISTS(crls->carl)){
        for(i=0; i<crls->carl.head->numberRevoked; i++){
            if(strstr(cmdChain[1]->name.server, crls->carl.list[i])!=NULL)
                return SK_API_REVOKED_SERVER;
        }
    }
    if(RL_EXISTS(crls->cprl)){
        for(i=0; i<crls->cprl.head->numberRevoked; i++){
            if(strstr(cmdChain[0]->name.server, crls->cprl.list[i])!=NULL)
                return SK_API_REVOKED_SERVER;
        }
    }

    return SK_API_SUCCESS;
}

int rlPtrsValid(BbAppLaunchCrls *crls)
{
    BbCrlBundle *rl;
    int i;

    for(i=0, rl=(BbCrlBundle *)crls;
        i<sizeof(BbAppLaunchCrls)/sizeof(BbCrlBundle);
        i++, rl++){
        if(!RL_EXISTS(*rl))
            continue;
        if(!ptrValid(rl->head, sizeof *rl->head, 4))
            return 0;
        if(!ptrValid(rl->list, sizeof(BbCrlEntry)*rl->head->numberRevoked, 4))
            return 0;
        if(rl->head->type!=BB_CRL_TYPE_CA && 
           !certChainPtrsValid(rl->certChain)){
            return 0;
        }
    }
    return 1;
}