// verify a signature against a public sas key.
int crypto_verify_signature(unsigned char *sas_key, 
			    unsigned char *content, int content_len, 
			    unsigned char *signature_block, int signature_len)
{
  IN();
  
  if (signature_len!=SIGNATURE_BYTES)
    RETURN(WHY("Invalid signature length"));
  
  /* reconstitute signed message by putting hash at end of signature */
  unsigned char reassembled[signature_len + content_len];
  bcopy(signature_block, reassembled, signature_len);
  bcopy(content, &reassembled[signature_len], content_len);
  
  /* verify signature.
   Note that crypto_sign_open requires m to be as large as signature, even
   though it will not need the whole length eventually -- it does use the 
   full length and will overwrite the end of a short buffer. */
  unsigned char message[sizeof(reassembled)+64];
  unsigned long long  mlen=0;
  int result
  =crypto_sign_edwards25519sha512batch_open(message,&mlen,
					    reassembled,sizeof(reassembled),
					    sas_key);
  
  if (result)
    RETURN(WHY("Signature verification failed"));
  RETURN(0);
}
Exemple #2
0
int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp)
{
  IN();

  int len=f->payload->sizeLimit - f->payload->position;
  unsigned char *b = NULL;
  unsigned char plain_block[len+16];

  /* Indicate MDP message type */
  mdp->packetTypeAndFlags=MDP_TX;
  
  switch(f->modifiers&OF_CRYPTO_BITS)  {
  case 0: 
    /* get payload */
    b=&f->payload->bytes[f->payload->position];
    mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN;
    break;
  case OF_CRYPTO_CIPHERED:
    RETURN(WHY("decryption not implemented"));
      
  case OF_CRYPTO_SIGNED:
    {
      /* This call below will dispatch the request for the SAS if we don't
	 already have it.  In the meantime, we just drop the frame if the SAS
	 is not available. */
      
      if (!f->source->sas_valid){
	keyring_send_sas_request(f->source);
	RETURN(WHY("SAS key not currently on record, cannot verify"));
      }
      
      /* get payload and following compacted signature */
      b=&f->payload->bytes[f->payload->position];
      len=f->payload->sizeLimit - f->payload->position - crypto_sign_edwards25519sha512batch_BYTES;

      /* reconstitute signature by putting hash between two halves of signature */
      unsigned char signature[crypto_hash_sha512_BYTES
			      +crypto_sign_edwards25519sha512batch_BYTES];
      bcopy(&b[len],&signature[0],32);
      
      crypto_hash_sha512(&signature[32],b,len);
      if (0) dump("hash for verification",&signature[32],crypto_hash_sha512_BYTES);
      
      bcopy(&b[len+32],&signature[32+crypto_hash_sha512_BYTES],32);
      
      /* verify signature */
      unsigned char m[crypto_hash_sha512_BYTES];
      unsigned long long  mlen=0;
      int result
	=crypto_sign_edwards25519sha512batch_open(m,&mlen,
						  signature,sizeof(signature),
						  f->source->sas_public);
      if (result) {
	WHY("Signature verification failed");
	dump("data", b, len);
	dump("signature", signature, sizeof(signature));
	RETURN(-1);
      } else if (0) DEBUG("signature check passed");
    }    
    mdp->packetTypeAndFlags|=MDP_NOCRYPT; 
    break;
  case OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED:
    {
      if (0) DEBUGF("crypted MDP frame for %s", alloca_tohex_sid(mdp->out.dst.sid));

      unsigned char *k=keyring_get_nm_bytes(&mdp->out.dst,&mdp->out.src);
      unsigned char *nonce=&f->payload->bytes[f->payload->position];
      int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
      int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
      if (!k) 
	RETURN(WHY("I don't have the private key required to decrypt that"));
      bzero(&plain_block[0],crypto_box_curve25519xsalsa20poly1305_ZEROBYTES-16);
      int cipher_len=f->payload->sizeLimit - f->payload->position - nb;
      bcopy(&f->payload->bytes[nb + f->payload->position],&plain_block[16],cipher_len);
      if (0) {
	dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES);
	dump("nonce",nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
	dump("cipher block",&plain_block[16],cipher_len); 
      }
      if (crypto_box_curve25519xsalsa20poly1305_open_afternm
	  (plain_block,plain_block,cipher_len+16,nonce,k)) {
	RETURN(WHYF("crypto_box_open_afternm() failed (forged or corrupted packet of %d bytes)",cipher_len+16));
      }
      if (0) dump("plain block",&plain_block[zb],cipher_len-16);
      b=&plain_block[zb];
      len=cipher_len-16;
      break;
    }    
  }
  
  if (!b)
    RETURN(WHY("Failed to decode mdp payload"));
  
  int version=(b[0]<<8)+b[1];
  if (version!=0x0101) RETURN(WHY("Saw unsupported MDP frame version"));
  
  /* extract MDP port numbers */
  mdp->in.src.port=(b[2]<<24)+(b[3]<<16)+(b[4]<<8)+b[5];
  mdp->in.dst.port=(b[6]<<24)+(b[7]<<16)+(b[8]<<8)+b[9];
  if (0) DEBUGF("RX mdp dst.port=%d, src.port=%d", mdp->in.dst.port, mdp->in.src.port);  
  
  mdp->in.payload_length=len-10;
  bcopy(&b[10],&mdp->in.payload[0],mdp->in.payload_length);
  
  RETURN(0);
}
Exemple #3
0
static int keyring_send_sas_request_client(struct subscriber *subscriber){
  int sent, client_port, found = 0, ret = 0;
  int siglen=SID_SIZE+crypto_sign_edwards25519sha512batch_BYTES;
  unsigned char *srcsid[SID_SIZE] = {0}, *plain = NULL;
  unsigned char signature[siglen];
  time_ms_t now = gettime_ms();
  
  CHECK_ERR(overlay_mdp_getmyaddr(0,(sid_t *)srcsid) == 0,"Could not get local address");

  if (subscriber->sas_valid)
    return 1;
  
  CHECK_ERR(now >= subscriber->sas_last_request + 100,"Too soon to ask for SAS mapping again");
  
  CHECK_ERR(my_subscriber,"couldn't request SAS (I don't know who I am)");
  
  DEBUG("Requesting SAS mapping for SID=%s", alloca_tohex_sid(subscriber->sid));
  
  CHECK_ERR(overlay_mdp_bind((sid_t *)my_subscriber->sid,(client_port=32768+(random()&32767))) == 0,"Failed to bind to client socket");

/* request mapping (send request auth-crypted). */
  overlay_mdp_frame mdp;
  memset(&mdp,0,sizeof(mdp));  

  mdp.packetTypeAndFlags=MDP_TX;
  mdp.out.queue=OQ_MESH_MANAGEMENT;
  memmove(mdp.out.dst.sid,subscriber->sid,SID_SIZE);
  mdp.out.dst.port=MDP_PORT_KEYMAPREQUEST;
  mdp.out.src.port=client_port;
  memmove(mdp.out.src.sid,srcsid,SID_SIZE);
  mdp.out.payload_length=1;
  mdp.out.payload[0]=KEYTYPE_CRYPTOSIGN;
  
  sent = overlay_mdp_send(&mdp, 0,0);
  if (sent) {
    DEBUG("Failed to send SAS resolution request: %d", sent);
    CHECK_ERR(mdp.packetTypeAndFlags != MDP_ERROR,"MDP Server error #%d: '%s'",mdp.error.error,mdp.error.message);
  }
  
  time_ms_t timeout = now + 5000;

  while(now<timeout) {
    time_ms_t timeout_ms = timeout - gettime_ms();
    int result = overlay_mdp_client_poll(timeout_ms);
    
    if (result>0) {
      int ttl=-1;
      if (overlay_mdp_recv(&mdp, client_port, &ttl)==0) {
	switch(mdp.packetTypeAndFlags&MDP_TYPE_MASK) {
	  case MDP_ERROR:
	    ERROR("overlay_mdp_recv: %s (code %d)", mdp.error.message, mdp.error.error);
	    break;
	  case MDP_TX:
	  {
	    DEBUG("Received SAS mapping response");
	    found = 1;
	    break;
	  }
	  break;
	  default:
	    DEBUG("overlay_mdp_recv: Unexpected MDP frame type 0x%x", mdp.packetTypeAndFlags);
	    break;
	}
	if (found) break;
      }
    }
    now=gettime_ms();
    if (servalShutdown)
      break;
  }

  unsigned keytype = mdp.out.payload[0];
  
  CHECK_ERR(keytype == KEYTYPE_CRYPTOSIGN,"Ignoring SID:SAS mapping with unsupported key type %u", keytype);
  
  CHECK_ERR(mdp.out.payload_length >= 1 + SAS_SIZE,"Truncated key mapping announcement? payload_length: %d", mdp.out.payload_length);
  
  plain = (unsigned char*)calloc(mdp.out.payload_length,sizeof(unsigned char));
  unsigned long long plain_len=0;
  unsigned char *sas_public=&mdp.out.payload[1];
  unsigned char *compactsignature = &mdp.out.payload[1+SAS_SIZE];
  
  /* reconstitute signed SID for verification */
  memmove(&signature[0],&compactsignature[0],64);
  memmove(&signature[64],&mdp.out.src.sid[0],SID_SIZE);
  
  int r=crypto_sign_edwards25519sha512batch_open(plain,&plain_len,
						 signature,siglen,
						 sas_public);
  CHECK_ERR(r == 0,"SID:SAS mapping verification signature does not verify");

  /* These next two tests should never be able to fail, but let's just check anyway. */
  CHECK_ERR(plain_len == SID_SIZE,"SID:SAS mapping signed block is wrong length");
  CHECK_ERR(memcmp(plain, mdp.out.src.sid, SID_SIZE) == 0,"SID:SAS mapping signed block is for wrong SID");
  
  memmove(subscriber->sas_public, sas_public, SAS_SIZE);
  subscriber->sas_valid=1;
  subscriber->sas_last_request=now;
  ret = 1;
  
error:
  if (plain) free(plain);
  return ret;
}