/*---------------------------------------------------------------------------*/ int p_broadcast_send(struct p_broadcast_conn *c, const void *data, size_t length) { PRINTF("[pbroadcast.c] Sending message of size %d\n", (int)length); if (length > MAX_BROADCAST_PAYLOAD_SIZE) { PRINTF("[pbroadcast.c] ^ Error: Broadcast packet is too long.\n"); return 0; } if (c == NULL) { PRINTF("[pbroadcast.c] ^ Error: Broadcast Connection is NULL\n"); return 0; } packetbuf_clear(); packetbuf_set_addr(PACKETBUF_ADDR_SENDER, &linkaddr_node_addr); packetbuf_set_datalen(length + sizeof(uint16_t)); // copy payload into packet memcpy(packetbuf_dataptr(), data, length); // copy hash to end of packet uint16_t hash = packet_hash(data, length); memcpy(packetbuf_dataptr() + (uintptr_t)length, &hash, sizeof(uint16_t)); PRINTF("[pbroadcast.c] ^ Hash: %02X Datalen: %d\n", hash, packetbuf_datalen()); PRINTF("[pbroadcast.c] ^ Data: "); DEBUG_DUMP_DATA(packetbuf_dataptr(), packetbuf_datalen()); PRINTF("\n"); int status = abc_send(&(c->abc)); if (status == 0) { PRINTF("[pbroadcast.c] Broadcast could not be sent.\n"); } return status; }
/*---------------------------------------------------------------------------*/ static void recv_from_abc(struct abc_conn *bc) { if (bc == NULL) { PRINTF("[pbroadcast.c] Error: ABC Connection is NULL\n"); return; } linkaddr_t sender; struct p_broadcast_conn *c = (struct p_broadcast_conn *)bc; linkaddr_copy(&sender, packetbuf_addr(PACKETBUF_ADDR_SENDER)); uint16_t actual_hash = packet_hash(packetbuf_dataptr(), packetbuf_datalen() - sizeof(uint16_t)); uint8_t *hash_ptr = packetbuf_dataptr() + (uintptr_t)(packetbuf_datalen() - sizeof(uint16_t)); uint16_t transmitted_hash = (hash_ptr[1] << 8) + (hash_ptr[0]); PRINTF("[pbroadcast.c] Received message of size %d from %d.%d.\n", packetbuf_datalen() - sizeof(uint16_t), sender.u8[0], sender.u8[1]); PRINTF("[pbroadcast.c] ^ Data: "); DEBUG_DUMP_DATA(packetbuf_dataptr(), packetbuf_datalen()); PRINTF("\n"); PRINTF("[pbroadcast.c] ^ Hash: %02X\n", transmitted_hash); if (actual_hash != transmitted_hash) { PRINTF("[pbroadcast.c] ^ Incorrect hash (expected %02X, but is %02X); discarding received packet.\n", transmitted_hash, actual_hash); return; } if (c->received) { c->received(c, &sender, packetbuf_dataptr(), packetbuf_datalen() - sizeof(uint16_t)); } }
int beginServerHandshake( INOUT SESSION_INFO *sessionInfoPtr, INOUT SSL_HANDSHAKE_INFO *handshakeInfo ) { STREAM *stream = &handshakeInfo->stream; SCOREBOARD_LOOKUP_RESULT lookupResult = DUMMY_INIT_STRUCT; MESSAGE_DATA msgData; int length, resumedSessionID = CRYPT_ERROR; int packetOffset, status; assert( isWritePtr( sessionInfoPtr, sizeof( SESSION_INFO ) ) ); assert( isWritePtr( handshakeInfo, sizeof( SSL_HANDSHAKE_INFO ) ) ); /* Read and process the client hello */ status = readHSPacketSSL( sessionInfoPtr, handshakeInfo, &length, SSL_MSG_FIRST_HANDSHAKE ); if( cryptStatusError( status ) ) return( status ); sMemConnect( stream, sessionInfoPtr->receiveBuffer, length ); status = processHelloSSL( sessionInfoPtr, handshakeInfo, stream, TRUE ); sMemDisconnect( stream ); if( cryptStatusError( status ) ) { if( status != OK_SPECIAL ) return( status ); /* The client has sent us a sessionID in an attempt to resume a previous session, see if it's in the session cache */ resumedSessionID = \ lookupScoreboardEntry( sessionInfoPtr->sessionSSL->scoreboardInfoPtr, SCOREBOARD_KEY_SESSIONID_SVR, handshakeInfo->sessionID, handshakeInfo->sessionIDlength, &lookupResult ); #ifdef CONFIG_SUITEB_TESTS resumedSessionID = CRYPT_ERROR; /* Disable for Suite B tests */ #endif /* CONFIG_SUITEB_TESTS */ } /* Handle session resumption. If it's a new session or the session data has expired from the cache, generate a new session ID */ if( cryptStatusError( resumedSessionID ) ) { setMessageData( &msgData, handshakeInfo->sessionID, SESSIONID_SIZE ); status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE ); if( cryptStatusError( status ) ) return( status ); handshakeInfo->sessionIDlength = SESSIONID_SIZE; } else { /* We're resuming a previous session, remember the premaster secret */ status = attributeCopyParams( handshakeInfo->premasterSecret, SSL_SECRET_SIZE, &handshakeInfo->premasterSecretSize, lookupResult.data, lookupResult.dataSize ); ENSURES( cryptStatusOK( status ) ); } /* Get the nonce that's used to randomise all crypto operations and set up the server DH/ECDH context if necessary */ setMessageData( &msgData, handshakeInfo->serverNonce, SSL_NONCE_SIZE ); status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_GETATTRIBUTE_S, &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE ); if( cryptStatusOK( status ) && isKeyxAlgo( handshakeInfo->keyexAlgo ) ) { status = initDHcontextSSL( &handshakeInfo->dhContext, NULL, 0, ( handshakeInfo->authAlgo != CRYPT_ALGO_NONE ) ? \ sessionInfoPtr->privateKey : CRYPT_UNUSED, isEccAlgo( handshakeInfo->keyexAlgo ) ? \ handshakeInfo->eccCurveID : CRYPT_ECCCURVE_NONE ); } if( cryptStatusError( status ) ) return( status ); /* Build the server hello, certificate, optional certificate request, and done packets: byte ID = SSL_HAND_SERVER_HELLO uint24 len byte[2] version = { 0x03, 0x0n } byte[32] nonce byte sessIDlen byte[] sessID uint16 suite byte copr = 0 [ uint16 extListLen -- RFC 3546/RFC 4366 byte extType uint16 extLen byte[] extData ] ... We have to be careful how we handle extensions because the RFC makes the rather optimistic assumption that implementations can handle the presence of unexpected data at the end of the hello packet, to avoid problems with this we avoid sending extensions unless they're in response to extensions already sent by the client */ status = openPacketStreamSSL( stream, sessionInfoPtr, CRYPT_USE_DEFAULT, SSL_MSG_HANDSHAKE ); if( cryptStatusError( status ) ) return( status ); status = continueHSPacketStream( stream, SSL_HAND_SERVER_HELLO, &packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } sputc( stream, SSL_MAJOR_VERSION ); sputc( stream, sessionInfoPtr->version ); swrite( stream, handshakeInfo->serverNonce, SSL_NONCE_SIZE ); sputc( stream, handshakeInfo->sessionIDlength ); swrite( stream, handshakeInfo->sessionID, handshakeInfo->sessionIDlength ); writeUint16( stream, handshakeInfo->cipherSuite ); status = sputc( stream, 0 ); /* No compression */ if( handshakeInfo->hasExtensions ) status = writeServerExtensions( stream, handshakeInfo ); if( cryptStatusOK( status ) ) status = completeHSPacketStream( stream, packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } /* If it's a resumed session then the server hello is followed immediately by the change cipherspec, which is sent by the shared handshake completion code */ if( !cryptStatusError( resumedSessionID ) ) { status = completePacketStreamSSL( stream, 0 ); if( cryptStatusOK( status ) ) status = hashHSPacketWrite( handshakeInfo, stream, 0 ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } /* Tell the caller that it's a resumed session, leaving the stream open in order to write the change cipherspec message that follows the server hello in a resumed session */ DEBUG_PRINT(( "Resuming session with client based on " "sessionID = \n" )); DEBUG_DUMP_DATA( handshakeInfo->sessionID, handshakeInfo->sessionIDlength ); return( OK_SPECIAL ); } /* ... (optional server supplemental data) byte ID = SSL_HAND_SUPPLEMENTAL_DATA uint24 len uint16 type uint16 len byte[] value ... */ /* ... (optional server certificate chain) ... */ if( handshakeInfo->authAlgo != CRYPT_ALGO_NONE ) { status = writeSSLCertChain( sessionInfoPtr, stream ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } } /* ... (optional server keyex) byte ID = SSL_HAND_SERVER_KEYEXCHANGE uint24 len DH: uint16 dh_pLen byte[] dh_p uint16 dh_gLen byte[] dh_g uint16 dh_YsLen byte[] dh_Ys [ byte hashAlgoID -- TLS 1.2 ] [ byte sigAlgoID -- TLS 1.2 ] uint16 signatureLen byte[] signature ECDH: byte curveType uint16 namedCurve uint8 ecPointLen -- NB uint8 not uint16 byte[] ecPoint [ byte hashAlgoID -- TLS 1.2 ] [ byte sigAlgoID -- TLS 1.2 ] uint16 signatureLen byte[] signature */ if( isKeyxAlgo( handshakeInfo->keyexAlgo ) ) { KEYAGREE_PARAMS keyAgreeParams; void *keyData = DUMMY_INIT_PTR; int keyDataOffset, keyDataLength = DUMMY_INIT; /* Perform phase 1 of the DH/ECDH key agreement process */ memset( &keyAgreeParams, 0, sizeof( KEYAGREE_PARAMS ) ); status = krnlSendMessage( handshakeInfo->dhContext, IMESSAGE_CTX_ENCRYPT, &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) ); if( cryptStatusError( status ) ) { zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) ); sMemDisconnect( stream ); return( status ); } /* Write the DH/ECDH key parameters and public value and sign them */ status = continueHSPacketStream( stream, SSL_HAND_SERVER_KEYEXCHANGE, &packetOffset ); if( cryptStatusError( status ) ) { zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) ); sMemDisconnect( stream ); return( status ); } keyDataOffset = stell( stream ); status = exportAttributeToStream( stream, handshakeInfo->dhContext, CRYPT_IATTRIBUTE_KEY_SSL ); if( cryptStatusOK( status ) ) { if( isEccAlgo( handshakeInfo->keyexAlgo ) ) { sputc( stream, keyAgreeParams.publicValueLen ); swrite( stream, keyAgreeParams.publicValue, keyAgreeParams.publicValueLen ); } else { status = writeInteger16U( stream, keyAgreeParams.publicValue, keyAgreeParams.publicValueLen ); } } if( cryptStatusOK( status ) ) { keyDataLength = stell( stream ) - keyDataOffset; status = sMemGetDataBlockAbs( stream, keyDataOffset, &keyData, keyDataLength ); } if( cryptStatusOK( status ) ) { status = createKeyexSignature( sessionInfoPtr, handshakeInfo, stream, keyData, keyDataLength ); } zeroise( &keyAgreeParams, sizeof( KEYAGREE_PARAMS ) ); if( cryptStatusOK( status ) ) status = completeHSPacketStream( stream, packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } } /* ... (optional request for client certificate authentication) byte ID = SSL_HAND_SERVER_CERTREQUEST uint24 len byte certTypeLen byte[] certType = { RSA, DSA, ECDSA } [ uint16 sigHashListLen -- TLS 1.2 ] [ byte hashAlgoID -- TLS 1.2 ] [ byte sigAlgoID -- TLS 1.2 ] uint16 caNameListLen = 4 uint16 caNameLen = 2 byte[] caName = { 0x30, 0x00 } ... */ if( clientCertAuthRequired( sessionInfoPtr ) ) { status = continueHSPacketStream( stream, SSL_HAND_SERVER_CERTREQUEST, &packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } status = writeCertRequest( sessionInfoPtr, handshakeInfo, stream ); if( cryptStatusOK( status ) ) status = completeHSPacketStream( stream, packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } } /* ... byte ID = SSL_HAND_SERVER_HELLODONE uint24 len = 0 */ status = continueHSPacketStream( stream, SSL_HAND_SERVER_HELLODONE, &packetOffset ); if( cryptStatusOK( status ) ) status = completeHSPacketStream( stream, packetOffset ); if( cryptStatusError( status ) ) { sMemDisconnect( stream ); return( status ); } /* Send the combined server packets to the client. We perform the assorted hashing of the packets in between the network ops where it's effectively free */ status = sendPacketSSL( sessionInfoPtr, stream, FALSE ); if( cryptStatusOK( status ) ) status = hashHSPacketWrite( handshakeInfo, stream, 0 ); sMemDisconnect( stream ); return( status ); }