Пример #1
0
void SleepForUpTicks( uint64_t inTicks )
{
    uint64_t  ticks, deadline;

    ticks = UpTicks();
    deadline = ticks + inTicks;
    for( ; ticks < deadline; ticks = UpTicks() )
    {
        ticks = deadline - ticks;
        msleep(ticks);
    }
}
Пример #2
0
static OSStatus
    __MFiSAP_Exchange_ServerM1( 
        MFiSAPRef       inRef, 
        const uint8_t * inInputPtr,
        size_t          inInputLen, 
        uint8_t **      outOutputPtr,
        size_t *        outOutputLen )
{
    OSStatus            err;
    const uint8_t *     inputEnd;
    const uint8_t *     clientECDHPublicKey;
    uint8_t             ourPrivateKey[ kMFiSAP_ECDHKeyLen ];
    uint8_t             ourPublicKey[ kMFiSAP_ECDHKeyLen ];
    SHA_CTX             sha1Context;
    uint8_t             digest[ 20 ];
    uint8_t *           signaturePtr = NULL;
    size_t              signatureLen;
    uint8_t *           certificatePtr = NULL;
    size_t              certificateLen;
    uint8_t             aesMasterKey[ kMFiSAP_AESKeyLen ];
    uint8_t             aesMasterIV[ kMFiSAP_AESKeyLen ];
    uint8_t *           buf;
    uint8_t *           dst;
    size_t              len;

    if( ( UpTicks() - gMFiSAP_LastTicks ) < UpTicksPerSecond() )
    {
        if( gMFiSAP_ThrottleCounter < 4 ) ++gMFiSAP_ThrottleCounter;
        SleepForUpTicks( gMFiSAP_ThrottleCounter * UpTicksPerSecond() );
    }
    else
    {
        gMFiSAP_ThrottleCounter = 0;
    }
    gMFiSAP_LastTicks = UpTicks();

    // Validate inputs. Input data must be: <1:version> <32:client's ECDH public key>.

    inputEnd = inInputPtr + inInputLen;
    require_action( inputEnd > inInputPtr, exit, err = kSizeErr ); // Detect bad length causing ptr wrap.

    require_action( ( inputEnd - inInputPtr ) >= kMFiSAP_VersionLen, exit, err = kSizeErr );
    inRef->version = *inInputPtr++;
    require_action( inRef->version == kMFiSAPVersion1, exit, err = kVersionErr );

    require_action( ( inputEnd - inInputPtr ) >= kMFiSAP_ECDHKeyLen, exit, err = kSizeErr );
    clientECDHPublicKey = inInputPtr;
    inInputPtr += kMFiSAP_ECDHKeyLen;

    require_action( inInputPtr == inputEnd, exit, err = kSizeErr );

    // Generate a random ECDH key pair.

    err = PlatformRandomBytes( ourPrivateKey, sizeof( ourPrivateKey ) );
    require_noerr( err, exit );
    curve25519_donna( ourPublicKey, ourPrivateKey, NULL );

    // Use our private key and the client's public key to generate the shared secret.
    // Hash the shared secret and truncate it to form the AES master key.
    // Hash the shared secret with salt to derive the AES master IV.

    curve25519_donna( inRef->sharedSecret, ourPrivateKey, clientECDHPublicKey );
    SHA1_Init( &sha1Context );
    SHA1_Update( &sha1Context, kMFiSAP_AES_KEY_SaltPtr, kMFiSAP_AES_KEY_SaltLen );
    SHA1_Update( &sha1Context, inRef->sharedSecret, sizeof( inRef->sharedSecret ) );
    SHA1_Final( digest, &sha1Context );
    memcpy( aesMasterKey, digest, sizeof( aesMasterKey ) );

    SHA1_Init( &sha1Context );
    SHA1_Update( &sha1Context, kMFiSAP_AES_IV_SaltPtr, kMFiSAP_AES_IV_SaltLen );
    SHA1_Update( &sha1Context, inRef->sharedSecret, sizeof( inRef->sharedSecret ) );
    SHA1_Final( digest, &sha1Context );
    memcpy( aesMasterIV, digest, sizeof( aesMasterIV ) );

    // Use the auth chip to sign a hash of <32:our ECDH public key> <32:client's ECDH public key>.
    // And copy the auth chip's certificate so the client can verify the signature.

    SHA1_Init( &sha1Context );
    SHA1_Update( &sha1Context, ourPublicKey, sizeof( ourPublicKey ) );
    SHA1_Update( &sha1Context, clientECDHPublicKey, kMFiSAP_ECDHKeyLen );
    SHA1_Final( digest, &sha1Context );
    err = PlatformMFiAuthCreateSignature( digest, sizeof( digest ), &signaturePtr, &signatureLen );
    require_noerr( err, exit );

    err = PlatformMFiAuthCopyCertificate( &certificatePtr, &certificateLen );
    require_noerr( err, exit );

    // Encrypt the signature with the AES master key and master IV.
    
    err = AES_CTR_Init( &inRef->aesMasterContext, aesMasterKey, aesMasterIV );
    require_noerr( err, exit );

    err = AES_CTR_Update( &inRef->aesMasterContext, signaturePtr, signatureLen, signaturePtr );
    if( err ) AES_CTR_Final( &inRef->aesMasterContext );
    require_noerr( err, exit );

    inRef->aesMasterValid = true;

    // Return the response:
    //
    //      <32:our ECDH public key>
    //      <4:big endian certificate length>
    //      <N:certificate data>
    //      <4:big endian signature length>
    //      <N:encrypted signature data>

    len = kMFiSAP_ECDHKeyLen + 4 + certificateLen + 4 + signatureLen;
    buf = (uint8_t *) malloc( len );
    require_action( buf, exit, err = kNoMemoryErr );
    dst = buf;

    memcpy( dst, ourPublicKey, sizeof( ourPublicKey ) );
    dst += sizeof( ourPublicKey );

    *dst++ = (uint8_t)( ( certificateLen >> 24 ) & 0xFF );
    *dst++ = (uint8_t)( ( certificateLen >> 16 ) & 0xFF );
    *dst++ = (uint8_t)( ( certificateLen >>  8 ) & 0xFF );
    *dst++ = (uint8_t)(   certificateLen         & 0xFF );
    memcpy( dst, certificatePtr, certificateLen );
    dst += certificateLen;

    *dst++ = (uint8_t)( ( signatureLen >> 24 ) & 0xFF );
    *dst++ = (uint8_t)( ( signatureLen >> 16 ) & 0xFF );
    *dst++ = (uint8_t)( ( signatureLen >>  8 ) & 0xFF );
    *dst++ = (uint8_t)(   signatureLen         & 0xFF );
    memcpy( dst, signaturePtr, signatureLen );
    dst += signatureLen;

    check( dst == ( buf + len ) );
    *outOutputPtr = buf;
    *outOutputLen = (size_t)( dst - buf );

exit:
    if( certificatePtr )    free( certificatePtr );
    if( signaturePtr )      free( signaturePtr );
    return( err );
}