コード例 #1
0
ファイル: proto.c プロジェクト: AsherBond/cf22cf3
void CheckRemoteVersion()

{ char sendbuffer[CF_BUFSIZE];
  char recvbuffer[CF_BUFSIZE];
  int tosend;

Debug("CheckRemoteVersion\n");  
snprintf(sendbuffer,CF_BUFSIZE,"VERSION");
tosend = strlen(sendbuffer);

if (SendTransaction(CONN->sd,sendbuffer,tosend,CF_DONE) == -1)
   {
   snprintf(OUTPUT,CF_BUFSIZE*2,"Transmission failed while checking version");
   CfLog(cfinform,OUTPUT,"send");
   return;
   }

if (ReceiveTransaction(CONN->sd,recvbuffer,NULL) == -1)
   {
   snprintf(OUTPUT,CF_BUFSIZE*2,"Reply failed while checking version");
   CfLog(cfinform,OUTPUT,"send");
   CONN->protoversion = 0;
   return;
   }

if (BadProtoReply(recvbuffer))
   {
   CONN->protoversion = 0;
   return;
   }
else
   {
   CONN->protoversion = 1;
   return;
   }
}
コード例 #2
0
ファイル: client_protocol.c プロジェクト: AsherBond/core
int AuthenticateAgent(AgentConnection *conn, bool trust_key)
{
    char sendbuffer[CF_EXPANDSIZE], in[CF_BUFSIZE], *out, *decrypted_cchall;
    BIGNUM *nonce_challenge, *bn = NULL;
    unsigned char digest[EVP_MAX_MD_SIZE];
    int encrypted_len, nonce_len = 0, len, session_size;
    bool need_to_implicitly_trust_server;
    char enterprise_field = 'c';
    RSA *server_pubkey = NULL;

    if ((PUBKEY == NULL) || (PRIVKEY == NULL))
    {
        /* Try once more to load the keys, maybe the system is converging. */
        LoadSecretKeys();
        if ((PUBKEY == NULL) || (PRIVKEY == NULL))
        {
            char *pubkeyfile = PublicKeyFile(GetWorkDir());
            Log(LOG_LEVEL_ERR, "No public/private key pair found at: %s", pubkeyfile);
            free(pubkeyfile);
            return false;
        }
    }

    enterprise_field = CfEnterpriseOptions();
    session_size = CfSessionKeySize(enterprise_field);

/* Generate a random challenge to authenticate the server */

    nonce_challenge = BN_new();
    if (nonce_challenge == NULL)
    {
        Log(LOG_LEVEL_ERR, "Cannot allocate BIGNUM structure for server challenge");
        return false;
    }

    BN_rand(nonce_challenge, CF_NONCELEN, 0, 0);
    nonce_len = BN_bn2mpi(nonce_challenge, in);

    if (FIPS_MODE)
    {
        HashString(in, nonce_len, digest, CF_DEFAULT_DIGEST);
    }
    else
    {
        HashString(in, nonce_len, digest, HASH_METHOD_MD5);
    }

/* We assume that the server bound to the remote socket is the official one i.e. = root's */

    /* Ask the server to send us the public key if we don't have it. */
    if ((server_pubkey = HavePublicKeyByIP(conn->username, conn->remoteip)))
    {
        need_to_implicitly_trust_server = false;
        encrypted_len = RSA_size(server_pubkey);
    }
    else
    {
        need_to_implicitly_trust_server = true;
        encrypted_len = nonce_len;
    }

// Server pubkey is what we want to has as a unique ID

    snprintf(sendbuffer, sizeof(sendbuffer), "SAUTH %c %d %d %c",
             need_to_implicitly_trust_server ? 'n': 'y',
             encrypted_len, nonce_len, enterprise_field);

    out = xmalloc(encrypted_len);

    if (server_pubkey != NULL)
    {
        if (RSA_public_encrypt(nonce_len, in, out, server_pubkey, RSA_PKCS1_PADDING) <= 0)
        {
            Log(LOG_LEVEL_ERR,
                "Public encryption failed. (RSA_public_encrypt: %s)",
            CryptoLastErrorString());
            free(out);
            RSA_free(server_pubkey);
            return false;
        }

        memcpy(sendbuffer + CF_RSA_PROTO_OFFSET, out, encrypted_len);
    }
    else
    {
        memcpy(sendbuffer + CF_RSA_PROTO_OFFSET, in, nonce_len);
    }

/* proposition C1 - Send challenge / nonce */

    SendTransaction(conn->conn_info, sendbuffer, CF_RSA_PROTO_OFFSET + encrypted_len, CF_DONE);

    BN_free(bn);
    BN_free(nonce_challenge);
    free(out);

/*Send the public key - we don't know if server has it */
/* proposition C2 */

    memset(sendbuffer, 0, CF_EXPANDSIZE);
    len = BN_bn2mpi(PUBKEY->n, sendbuffer);
    SendTransaction(conn->conn_info, sendbuffer, len, CF_DONE);        /* No need to encrypt the public key ... */

/* proposition C3 */
    memset(sendbuffer, 0, CF_EXPANDSIZE);
    len = BN_bn2mpi(PUBKEY->e, sendbuffer);
    SendTransaction(conn->conn_info, sendbuffer, len, CF_DONE);

/* check reply about public key - server can break conn_info here */

/* proposition S1 */
    memset(in, 0, CF_BUFSIZE);

    if (ReceiveTransaction(conn->conn_info, in, NULL) == -1)
    {
        Log(LOG_LEVEL_ERR, "Protocol transaction broken off (1). (ReceiveTransaction: %s)", GetErrorStr());
        RSA_free(server_pubkey);
        return false;
    }

    if (BadProtoReply(in))
    {
        Log(LOG_LEVEL_ERR, "Bad protocol reply: %s", in);
        RSA_free(server_pubkey);
        return false;
    }

/* Get challenge response - should be CF_DEFAULT_DIGEST of challenge */

/* proposition S2 */
    memset(in, 0, CF_BUFSIZE);

    if (ReceiveTransaction(conn->conn_info, in, NULL) == -1)
    {
        Log(LOG_LEVEL_ERR, "Protocol transaction broken off (2). (ReceiveTransaction: %s)", GetErrorStr());
        RSA_free(server_pubkey);
        return false;
    }

    /* Check if challenge reply was correct */
    if ((HashesMatch(digest, in, CF_DEFAULT_DIGEST)) ||
        (HashesMatch(digest, in, HASH_METHOD_MD5)))  // Legacy
    {
        if (need_to_implicitly_trust_server == false)
        {
            /* The IP was found in lastseen. */
            Log(LOG_LEVEL_VERBOSE,
                ".....................[.h.a.i.l.].................................");
            Log(LOG_LEVEL_VERBOSE,
                "Strong authentication of server '%s' connection confirmed",
                conn->this_server);
        }
        else                                /* IP was not found in lastseen */
        {
            if (trust_key)
            {
                Log(LOG_LEVEL_VERBOSE,
                    "Trusting server identity, promise to accept key from '%s' = '%s'",
                    conn->this_server, conn->remoteip);
            }
            else
            {
                Log(LOG_LEVEL_ERR,
                    "Not authorized to trust public key of server '%s' (trustkey = false)",
                    conn->this_server);
                RSA_free(server_pubkey);
                return false;
            }
        }
    }
    else
    {
        Log(LOG_LEVEL_ERR, "Challenge response from server '%s/%s' was incorrect", conn->this_server,
             conn->remoteip);
        RSA_free(server_pubkey);
        return false;
    }

/* Receive counter challenge from server */

/* proposition S3 */
    memset(in, 0, CF_BUFSIZE);
    encrypted_len = ReceiveTransaction(conn->conn_info, in, NULL);

    if (encrypted_len <= 0)
    {
        Log(LOG_LEVEL_ERR, "Protocol transaction sent illegal cipher length");
        RSA_free(server_pubkey);
        return false;
    }

    decrypted_cchall = xmalloc(encrypted_len);

    if (RSA_private_decrypt(encrypted_len, in, decrypted_cchall, PRIVKEY, RSA_PKCS1_PADDING) <= 0)
    {
        Log(LOG_LEVEL_ERR,
            "Private decrypt failed, abandoning. (RSA_private_decrypt: %s)",
            CryptoLastErrorString());
        RSA_free(server_pubkey);
        return false;
    }

/* proposition C4 */
    if (FIPS_MODE)
    {
        HashString(decrypted_cchall, nonce_len, digest, CF_DEFAULT_DIGEST);
    }
    else
    {
        HashString(decrypted_cchall, nonce_len, digest, HASH_METHOD_MD5);
    }

    if (FIPS_MODE)
    {
        SendTransaction(conn->conn_info, digest, CF_DEFAULT_DIGEST_LEN, CF_DONE);
    }
    else
    {
        SendTransaction(conn->conn_info, digest, CF_MD5_LEN, CF_DONE);
    }

    free(decrypted_cchall);

/* If we don't have the server's public key, it will be sent */

    if (server_pubkey == NULL)
    {
        RSA *newkey = RSA_new();

        Log(LOG_LEVEL_VERBOSE, "Collecting public key from server!");

        /* proposition S4 - conditional */
        if ((len = ReceiveTransaction(conn->conn_info, in, NULL)) <= 0)
        {
            Log(LOG_LEVEL_ERR, "Protocol error in RSA authentation from IP '%s'", conn->this_server);
            return false;
        }

        if ((newkey->n = BN_mpi2bn(in, len, NULL)) == NULL)
        {
            Log(LOG_LEVEL_ERR,
                "Private key decrypt failed. (BN_mpi2bn: %s)",
                CryptoLastErrorString());
            RSA_free(newkey);
            return false;
        }

        /* proposition S5 - conditional */

        if ((len = ReceiveTransaction(conn->conn_info, in, NULL)) <= 0)
        {
            Log(LOG_LEVEL_INFO, "Protocol error in RSA authentation from IP '%s'",
                 conn->this_server);
            RSA_free(newkey);
            return false;
        }

        if ((newkey->e = BN_mpi2bn(in, len, NULL)) == NULL)
        {
            Log(LOG_LEVEL_ERR,
                "Public key decrypt failed. (BN_mpi2bn: %s)",
                CryptoLastErrorString());
            RSA_free(newkey);
            return false;
        }

        server_pubkey = RSAPublicKey_dup(newkey);
        RSA_free(newkey);
    }
    assert(server_pubkey != NULL);

/* proposition C5 */

    if (!SetSessionKey(conn))
    {
        Log(LOG_LEVEL_ERR, "Unable to set session key");
        return false;
    }

    if (conn->session_key == NULL)
    {
        Log(LOG_LEVEL_ERR, "A random session key could not be established");
        RSA_free(server_pubkey);
        return false;
    }

    encrypted_len = RSA_size(server_pubkey);

    out = xmalloc(encrypted_len);

    if (RSA_public_encrypt(session_size, conn->session_key, out, server_pubkey, RSA_PKCS1_PADDING) <= 0)
    {
        Log(LOG_LEVEL_ERR,
            "Public encryption failed. (RSA_public_encrypt: %s)",
            CryptoLastErrorString());
        free(out);
        RSA_free(server_pubkey);
        return false;
    }

    SendTransaction(conn->conn_info, out, encrypted_len, CF_DONE);

    Key *key = KeyNew(server_pubkey, CF_DEFAULT_DIGEST);
    conn->conn_info->remote_key = key;

    Log(LOG_LEVEL_VERBOSE, "Public key identity of host '%s' is: %s",
        conn->remoteip, KeyPrintableHash(conn->conn_info->remote_key));

    SavePublicKey(conn->username, KeyPrintableHash(conn->conn_info->remote_key), server_pubkey);

    unsigned int length = 0;
    LastSaw(conn->remoteip, KeyBinaryHash(conn->conn_info->remote_key, &length), LAST_SEEN_ROLE_CONNECT);

    free(out);

    return true;
}
コード例 #3
0
ファイル: stat_cache.c プロジェクト: dstam/core
/**
 * @param #stattype should be either "link" or "file". If a link, this reads
 *                  readlink and sends it back in the same packet. It then
 *                  caches the value for each copy command.
 *
 */
int cf_remote_stat(AgentConnection *conn, bool encrypt, const char *file,
                   struct stat *statbuf, const char *stattype)
{
    assert(strcmp(stattype, "file") == 0 ||
           strcmp(stattype, "link") == 0);

    /* We encrypt only for CLASSIC protocol. The TLS protocol is always over
     * encrypted layer, so it does not support encrypted (S*) commands. */
    encrypt = encrypt && conn->conn_info->protocol == CF_PROTOCOL_CLASSIC;

    if (strlen(file) > CF_BUFSIZE - 30)
    {
        Log(LOG_LEVEL_ERR, "Filename too long");
        return -1;
    }

    int ret = StatFromCache(conn, file, statbuf, stattype);
    if (ret == 0 || ret == -1)                            /* found or error */
    {
        return ret;
    }

    /* Not found in cache */

    char recvbuffer[CF_BUFSIZE];
    memset(recvbuffer, 0, CF_BUFSIZE);

    time_t tloc = time(NULL);
    if (tloc == (time_t) -1)
    {
        Log(LOG_LEVEL_ERR, "Couldn't read system clock (time: %s)",
            GetErrorStr());
        tloc = 0;
    }

    char sendbuffer[CF_BUFSIZE];
    int tosend;
    sendbuffer[0] = '\0';

    if (encrypt)
    {
        if (conn->session_key == NULL)
        {
            Log(LOG_LEVEL_ERR,
                "Cannot do encrypted copy without keys (use cf-key)");
            return -1;
        }

        char in[CF_BUFSIZE], out[CF_BUFSIZE];

        snprintf(in, CF_BUFSIZE - 1, "SYNCH %jd STAT %s",
                 (intmax_t) tloc, file);
        int cipherlen = EncryptString(out, sizeof(out), in, strlen(in) + 1,
                                      conn->encryption_type, conn->session_key);

        tosend = cipherlen + CF_PROTO_OFFSET;

        if(tosend > sizeof(sendbuffer))
        {
            ProgrammingError("cf_remote_stat: tosend (%d) > sendbuffer (%ld)",
                             tosend, sizeof(sendbuffer));
        }

        snprintf(sendbuffer, CF_BUFSIZE - 1, "SSYNCH %d", cipherlen);
        memcpy(sendbuffer + CF_PROTO_OFFSET, out, cipherlen);
    }
    else
    {
        snprintf(sendbuffer, CF_BUFSIZE, "SYNCH %jd STAT %s",
                 (intmax_t) tloc, file);
        tosend = strlen(sendbuffer);
    }

    if (SendTransaction(conn->conn_info, sendbuffer, tosend, CF_DONE) == -1)
    {
        Log(LOG_LEVEL_INFO,
            "Transmission failed/refused talking to %.255s:%.255s. (stat: %s)",
            conn->this_server, file, GetErrorStr());
        return -1;
    }

    if (ReceiveTransaction(conn->conn_info, recvbuffer, NULL) == -1)
    {
        /* TODO mark connection in the cache as closed. */
        return -1;
    }

    if (strstr(recvbuffer, "unsynchronized"))
    {
        Log(LOG_LEVEL_ERR,
            "Clocks differ too much to do copy by date (security), server reported: %s",
            recvbuffer + strlen("BAD: "));
        return -1;
    }

    if (BadProtoReply(recvbuffer))
    {
        Log(LOG_LEVEL_VERBOSE, "Server returned error: %s",
            recvbuffer + strlen("BAD: "));
        errno = EPERM;
        return -1;
    }

    if (OKProtoReply(recvbuffer))
    {
        Stat cfst;

        // use intmax_t here to provide enough space for large values coming over the protocol
        intmax_t d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12 = 0, d13 = 0;
        ret = sscanf(recvbuffer, "OK: "
               "%1" PRIdMAX     // 01 cfst.cf_type
               " %5" PRIdMAX    // 02 cfst.cf_mode
               " %14" PRIdMAX   // 03 cfst.cf_lmode
               " %14" PRIdMAX   // 04 cfst.cf_uid
               " %14" PRIdMAX   // 05 cfst.cf_gid
               " %18" PRIdMAX   // 06 cfst.cf_size
               " %14" PRIdMAX   // 07 cfst.cf_atime
               " %14" PRIdMAX   // 08 cfst.cf_mtime
               " %14" PRIdMAX   // 09 cfst.cf_ctime
               " %1" PRIdMAX    // 10 cfst.cf_makeholes
               " %14" PRIdMAX   // 11 cfst.cf_ino
               " %14" PRIdMAX   // 12 cfst.cf_nlink
               " %18" PRIdMAX,  // 13 cfst.cf_dev
               &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9, &d10, &d11, &d12, &d13);

        if (ret < 13)
        {
            Log(LOG_LEVEL_ERR, "Cannot read SYNCH reply from '%s', only %d/13 items parsed", conn->remoteip, ret );
            return -1;
        }

        cfst.cf_type = (FileType) d1;
        cfst.cf_mode = (mode_t) d2;
        cfst.cf_lmode = (mode_t) d3;
        cfst.cf_uid = (uid_t) d4;
        cfst.cf_gid = (gid_t) d5;
        cfst.cf_size = (off_t) d6;
        cfst.cf_atime = (time_t) d7;
        cfst.cf_mtime = (time_t) d8;
        cfst.cf_ctime = (time_t) d9;
        cfst.cf_makeholes = (char) d10;
        cfst.cf_ino = d11;
        cfst.cf_nlink = d12;
        cfst.cf_dev = (dev_t)d13;

        /* Use %?d here to avoid memory overflow attacks */

        memset(recvbuffer, 0, CF_BUFSIZE);

        if (ReceiveTransaction(conn->conn_info, recvbuffer, NULL) == -1)
        {
            /* TODO mark connection in the cache as closed. */
            return -1;
        }

        if (strlen(recvbuffer) > 3)
        {
            cfst.cf_readlink = xstrdup(recvbuffer + 3);
        }
        else
        {
            cfst.cf_readlink = NULL;
        }

        switch (cfst.cf_type)
        {
        case FILE_TYPE_REGULAR:
            cfst.cf_mode |= (mode_t) S_IFREG;
            break;
        case FILE_TYPE_DIR:
            cfst.cf_mode |= (mode_t) S_IFDIR;
            break;
        case FILE_TYPE_CHAR_:
            cfst.cf_mode |= (mode_t) S_IFCHR;
            break;
        case FILE_TYPE_FIFO:
            cfst.cf_mode |= (mode_t) S_IFIFO;
            break;
        case FILE_TYPE_SOCK:
            cfst.cf_mode |= (mode_t) S_IFSOCK;
            break;
        case FILE_TYPE_BLOCK:
            cfst.cf_mode |= (mode_t) S_IFBLK;
            break;
        case FILE_TYPE_LINK:
            cfst.cf_mode |= (mode_t) S_IFLNK;
            break;
        }

        cfst.cf_filename = xstrdup(file);
        cfst.cf_server = xstrdup(conn->this_server);
        cfst.cf_failed = false;

        if (cfst.cf_lmode != 0)
        {
            cfst.cf_lmode |= (mode_t) S_IFLNK;
        }

        NewStatCache(&cfst, conn);

        if ((cfst.cf_lmode != 0) && (strcmp(stattype, "link") == 0))
        {
            statbuf->st_mode = cfst.cf_lmode;
        }
        else
        {
            statbuf->st_mode = cfst.cf_mode;
        }

        statbuf->st_uid = cfst.cf_uid;
        statbuf->st_gid = cfst.cf_gid;
        statbuf->st_size = cfst.cf_size;
        statbuf->st_mtime = cfst.cf_mtime;
        statbuf->st_ctime = cfst.cf_ctime;
        statbuf->st_atime = cfst.cf_atime;
        statbuf->st_ino = cfst.cf_ino;
        statbuf->st_dev = cfst.cf_dev;
        statbuf->st_nlink = cfst.cf_nlink;

        return 0;
    }

    Log(LOG_LEVEL_ERR, "Transmission refused or failed statting '%s', got '%s'", file, recvbuffer);
    errno = EPERM;
    return -1;
}
コード例 #4
0
ファイル: proto.c プロジェクト: AsherBond/cf22cf3
int KeyAuthentication(struct Image *ip)

{ char sendbuffer[CF_EXPANDSIZE],in[CF_BUFSIZE],*out,*decrypted_cchall;
 BIGNUM *nonce_challenge, *bn = NULL;
 unsigned long err;
 unsigned char digest[EVP_MAX_MD_SIZE];
 int encrypted_len,nonce_len = 0,len;
 char cant_trust_server, keyname[CF_BUFSIZE];
 RSA *server_pubkey = NULL;

if (COMPATIBILITY_MODE)
   {
   return true;
   }

if (PUBKEY == NULL || PRIVKEY == NULL) 
   {
   CfLog(cferror,"No public/private key pair found\n","");
   return false;
   }


/* Generate a random challenge to authenticate the server */
 
nonce_challenge = BN_new();
BN_rand(nonce_challenge,CF_NONCELEN,0,0);

nonce_len = BN_bn2mpi(nonce_challenge,in);
ChecksumString(in,nonce_len,digest,'m');

/* We assume that the server bound to the remote socket is the official one i.e. = root's */

if (OptionIs(CONTEXTID,"HostnameKeys",true))
   {
   snprintf(keyname,CF_BUFSIZE,"root-%s",ip->server); 
   Debug("KeyAuthentication(with hostname key %s)\n",keyname);
   }
else
   {
   snprintf(keyname,CF_BUFSIZE,"root-%s",CONN->remoteip); 
   Debug("KeyAuthentication(with IP keyname %s)\n",keyname);
   }

if (server_pubkey = HavePublicKey(keyname))
   {
   cant_trust_server = 'y';
   /* encrypted_len = BN_num_bytes(server_pubkey->n);*/   
   encrypted_len = RSA_size(server_pubkey);
   }
else 
   {
   cant_trust_server = 'n';                      /* have to trust server, since we can't verify id */
   encrypted_len = nonce_len;
   }

snprintf(sendbuffer,CF_BUFSIZE,"SAUTH %c %d %d",cant_trust_server,encrypted_len,nonce_len);
 
if ((out = malloc(encrypted_len)) == NULL)
   {
   FatalError("memory failure");
   }

if (server_pubkey != NULL)
   {
   if (RSA_public_encrypt(nonce_len,in,out,server_pubkey,RSA_PKCS1_PADDING) <= 0)
      {
      err = ERR_get_error();
      snprintf(OUTPUT,CF_BUFSIZE,"Public encryption failed = %s\n",ERR_reason_error_string(err));
      CfLog(cferror,OUTPUT,"");
      free(out);
      return false;
      }
   
   memcpy(sendbuffer+CF_RSA_PROTO_OFFSET,out,encrypted_len); 
   }
else
   {
   memcpy(sendbuffer+CF_RSA_PROTO_OFFSET,in,nonce_len); 
   }

/* proposition C1 - Send challenge / nonce */
 
SendTransaction(CONN->sd,sendbuffer,CF_RSA_PROTO_OFFSET+encrypted_len,CF_DONE);

BN_free(bn);
BN_free(nonce_challenge);
free(out);

if (DEBUG||D2)
   {
   RSA_print_fp(stdout,PUBKEY,0);
   }

/*Send the public key - we don't know if server has it */ 
/* proposition C2 */

memset(sendbuffer,0,CF_EXPANDSIZE); 
len = BN_bn2mpi(PUBKEY->n,sendbuffer); 
SendTransaction(CONN->sd,sendbuffer,len,CF_DONE); /* No need to encrypt the public key ... */

/* proposition C3 */ 
memset(sendbuffer,0,CF_EXPANDSIZE);   
len = BN_bn2mpi(PUBKEY->e,sendbuffer); 
SendTransaction(CONN->sd,sendbuffer,len,CF_DONE);

/* check reply about public key - server can break connection here */

/* proposition S1 */  
memset(in,0,CF_BUFSIZE);  

if (ReceiveTransaction(CONN->sd,in,NULL) == -1)
   {
   CfLog(cferror,"Protocol transaction broken off",NULL);
   return false;
   }

if (BadProtoReply(in))
   {
   CfLog(cferror,in,"");
   return false;
   }

/* Get challenge response - should be md5 of challenge */

/* proposition S2 */   
memset(in,0,CF_BUFSIZE);  

if (ReceiveTransaction(CONN->sd,in,NULL) == -1)
   {
   CfLog(cferror,"Protocol transaction broken off",NULL);
   return false;   
   }

if (!ChecksumsMatch(digest,in,'m')) 
   {
   snprintf(OUTPUT,CF_BUFSIZE,"Challenge response from server %s/%s was incorrect!",ip->server,CONN->remoteip);
   CfLog(cferror,OUTPUT,"");
   return false;
   }
else
   {
   char server[CF_EXPANDSIZE];
   ExpandVarstring(ip->server,server,NULL);
   
   if (cant_trust_server == 'y')  /* challenge reply was correct */ 
      {
      Verbose("\n...............................................................\n");
      snprintf(OUTPUT,CF_BUFSIZE,"Strong authentication of server=%s connection confirmed\n",server);
      CfLog(cfverbose,OUTPUT,"");
      }
   else
      {
      if (ip->trustkey == 'y')
         {
         snprintf(OUTPUT,CF_BUFSIZE,"Trusting server identity and willing to accept key from %s=%s",server,CONN->remoteip);
         CfLog(cferror,OUTPUT,"");
         }
      else
         {
         snprintf(OUTPUT,CF_BUFSIZE,"Not authorized to trust the server=%s's public key (trustkey=false)\n",server);
         CfLog(cferror,OUTPUT,"");
         return false;
         }
      }
   }

/* Receive counter challenge from server */ 

Debug("Receive counter challenge from server\n");  
/* proposition S3 */   
memset(in,0,CF_BUFSIZE);  
encrypted_len = ReceiveTransaction(CONN->sd,in,NULL);

if (encrypted_len < 0)
   {
   CfLog(cferror,"Protocol transaction sent illegal cipher length",NULL);
   return false;      
   }

if ((decrypted_cchall = malloc(encrypted_len)) == NULL)
   {
   FatalError("memory failure");
   }
 
if (RSA_private_decrypt(encrypted_len,in,decrypted_cchall,PRIVKEY,RSA_PKCS1_PADDING) <= 0)
   {
   err = ERR_get_error();
   snprintf(OUTPUT,CF_BUFSIZE,"Private decrypt failed = %s, abandoning\n",ERR_reason_error_string(err));
   CfLog(cferror,OUTPUT,"");
   return false;
   }

/* proposition C4 */   
ChecksumString(decrypted_cchall,nonce_len,digest,'m');
Debug("Replying to counter challenge with md5\n"); 
SendTransaction(CONN->sd,digest,16,CF_DONE);
free(decrypted_cchall); 

/* If we don't have the server's public key, it will be sent */


if (server_pubkey == NULL)
   {
   RSA *newkey = RSA_new();

   Debug("Collecting public key from server!\n"); 

   /* proposition S4 - conditional */  
   if ((len = ReceiveTransaction(CONN->sd,in,NULL)) <= 0)
      {
      CfLog(cferror,"Protocol error in RSA authentation from IP %s\n",ip->server);
      return false;
      }
   
   if ((newkey->n = BN_mpi2bn(in,len,NULL)) == NULL)
      {
      err = ERR_get_error();
      snprintf(OUTPUT,CF_BUFSIZE,"Private decrypt failed = %s\n",ERR_reason_error_string(err));
      CfLog(cferror,OUTPUT,"");
      RSA_free(newkey);
      return false;
      }

   /* proposition S5 - conditional */  
   if ((len=ReceiveTransaction(CONN->sd,in,NULL)) == 0)
      {
      CfLog(cfinform,"Protocol error in RSA authentation from IP %s\n",ip->server);
      RSA_free(newkey);
      return false;
      }
   
   if ((newkey->e = BN_mpi2bn(in,len,NULL)) == NULL)
      {
      err = ERR_get_error();
      snprintf(OUTPUT,CF_BUFSIZE,"Private decrypt failed = %s\n",ERR_reason_error_string(err));
      CfLog(cferror,OUTPUT,"");
      RSA_free(newkey);
      return false;
      }

   SavePublicKey(keyname,newkey);
   server_pubkey = RSAPublicKey_dup(newkey);
   RSA_free(newkey);
   }
 
/* proposition C5 */

GenerateRandomSessionKey();

DebugBinOut(CONN->session_key,CF_BLOWFISHSIZE);

if (CONN->session_key == NULL)
   {
   CfLog(cferror,"A random session key could not be established","");
   return false;
   }
else
   {
   Debug("Generated session key\n");
   DebugBinOut(CONN->session_key,CF_BLOWFISHSIZE);
   }

/* blowfishmpisize = BN_bn2mpi((BIGNUM *)CONN->session_key,in); */

DebugBinOut(CONN->session_key,CF_BLOWFISHSIZE);

encrypted_len = RSA_size(server_pubkey);

Debug("Encrypt %d to %d\n",CF_BLOWFISHSIZE,encrypted_len);

if ((out = malloc(encrypted_len)) == NULL)
   {
   FatalError("memory failure");
   }

if (RSA_public_encrypt(CF_BLOWFISHSIZE,CONN->session_key,out,server_pubkey,RSA_PKCS1_PADDING) <= 0)
   {
   err = ERR_get_error();
   snprintf(OUTPUT,CF_BUFSIZE,"Public encryption failed = %s\n",ERR_reason_error_string(err));
   CfLog(cferror,OUTPUT,"");
   free(out);
   return false;
   }

Debug("Encryption succeeded\n");

SendTransaction(CONN->sd,out,encrypted_len,CF_DONE);
DebugBinOut(out,encrypted_len);

if (server_pubkey != NULL)
   {
   RSA_free(server_pubkey);
   }

free(out);
return true; 
}
コード例 #5
0
ファイル: client_code.c プロジェクト: arcimboldo/cfengine
Item *RemoteDirList(const char *dirname, bool encrypt, AgentConnection *conn)
{
    char sendbuffer[CF_BUFSIZE];
    char recvbuffer[CF_BUFSIZE];
    char in[CF_BUFSIZE];
    char out[CF_BUFSIZE];
    int n, cipherlen = 0, tosend;
    char *sp;
    Item *files = NULL;
    Item *ret = NULL;

    if (strlen(dirname) > CF_BUFSIZE - 20)
    {
        Log(LOG_LEVEL_ERR, "Directory name too long");
        return NULL;
    }

    if (encrypt)
    {
        if (conn->session_key == NULL)
        {
            Log(LOG_LEVEL_ERR, "Cannot do encrypted copy without keys (use cf-key)");
            return NULL;
        }

        snprintf(in, CF_BUFSIZE, "OPENDIR %s", dirname);
        cipherlen = EncryptString(conn->encryption_type, in, out, conn->session_key, strlen(in) + 1);
        snprintf(sendbuffer, CF_BUFSIZE - 1, "SOPENDIR %d", cipherlen);
        memcpy(sendbuffer + CF_PROTO_OFFSET, out, cipherlen);
        tosend = cipherlen + CF_PROTO_OFFSET;
    }
    else
    {
        snprintf(sendbuffer, CF_BUFSIZE, "OPENDIR %s", dirname);
        tosend = strlen(sendbuffer);
    }

    if (SendTransaction(conn->sd, sendbuffer, tosend, CF_DONE) == -1)
    {
        return NULL;
    }

    while (true)
    {
        if ((n = ReceiveTransaction(conn->sd, recvbuffer, NULL)) == -1)
        {
            return NULL;
        }

        if (n == 0)
        {
            break;
        }

        if (encrypt)
        {
            memcpy(in, recvbuffer, n);
            DecryptString(conn->encryption_type, in, recvbuffer, conn->session_key, n);
        }

        if (FailedProtoReply(recvbuffer))
        {
            Log(LOG_LEVEL_INFO, "Network access to '%s:%s' denied", conn->this_server, dirname);
            return NULL;
        }

        if (BadProtoReply(recvbuffer))
        {
            Log(LOG_LEVEL_INFO, "%s", recvbuffer + 4);
            return NULL;
        }

        for (sp = recvbuffer; *sp != '\0'; sp++)
        {
            Item *ip;

            if (strncmp(sp, CFD_TERMINATOR, strlen(CFD_TERMINATOR)) == 0)       /* End transmission */
            {
                return ret;
            }

            ip = xcalloc(1, sizeof(Item));
            ip->name = (char *) AllocateDirentForFilename(sp);

            if (files == NULL)  /* First element */
            {
                ret = ip;
                files = ip;
            }
            else
            {
                files->next = ip;
                files = ip;
            }

            while (*sp != '\0')
            {
                sp++;
            }
        }
    }

    return ret;
}
コード例 #6
0
ファイル: client_code.c プロジェクト: arcimboldo/cfengine
int cf_remote_stat(char *file, struct stat *buf, char *stattype, bool encrypt, AgentConnection *conn)
/* If a link, this reads readlink and sends it back in the same
   package. It then caches the value for each copy command */
{
    char sendbuffer[CF_BUFSIZE];
    char recvbuffer[CF_BUFSIZE];
    char in[CF_BUFSIZE], out[CF_BUFSIZE];
    int ret, tosend, cipherlen;
    time_t tloc;

    memset(recvbuffer, 0, CF_BUFSIZE);

    if (strlen(file) > CF_BUFSIZE - 30)
    {
        Log(LOG_LEVEL_ERR, "Filename too long");
        return -1;
    }

    ret = CacheStat(file, buf, stattype, conn);

    if (ret != 0)
    {
        return ret;
    }

    if ((tloc = time((time_t *) NULL)) == -1)
    {
        Log(LOG_LEVEL_ERR, "Couldn't read system clock");
    }

    sendbuffer[0] = '\0';

    if (encrypt)
    {
        if (conn->session_key == NULL)
        {
            Log(LOG_LEVEL_ERR, "Cannot do encrypted copy without keys (use cf-key)");
            return -1;
        }

        snprintf(in, CF_BUFSIZE - 1, "SYNCH %jd STAT %s", (intmax_t) tloc, file);
        cipherlen = EncryptString(conn->encryption_type, in, out, conn->session_key, strlen(in) + 1);
        snprintf(sendbuffer, CF_BUFSIZE - 1, "SSYNCH %d", cipherlen);
        memcpy(sendbuffer + CF_PROTO_OFFSET, out, cipherlen);
        tosend = cipherlen + CF_PROTO_OFFSET;
    }
    else
    {
        snprintf(sendbuffer, CF_BUFSIZE, "SYNCH %jd STAT %s", (intmax_t) tloc, file);
        tosend = strlen(sendbuffer);
    }

    if (SendTransaction(conn->sd, sendbuffer, tosend, CF_DONE) == -1)
    {
        Log(LOG_LEVEL_INFO, "Transmission failed/refused talking to %.255s:%.255s. (stat: %s)",
            conn->this_server, file, GetErrorStr());
        return -1;
    }

    if (ReceiveTransaction(conn->sd, recvbuffer, NULL) == -1)
    {
        return -1;
    }

    if (strstr(recvbuffer, "unsynchronized"))
    {
        Log(LOG_LEVEL_ERR, "Clocks differ too much to do copy by date (security) '%s'", recvbuffer + 4);
        return -1;
    }

    if (BadProtoReply(recvbuffer))
    {
        Log(LOG_LEVEL_VERBOSE, "Server returned error '%s'", recvbuffer + 4);
        errno = EPERM;
        return -1;
    }

    if (OKProtoReply(recvbuffer))
    {
        Stat cfst;

        // use intmax_t here to provide enough space for large values coming over the protocol
        intmax_t d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12 = 0, d13 = 0;
        ret = sscanf(recvbuffer, "OK: "
               "%1" PRIdMAX     // 01 cfst.cf_type
               " %5" PRIdMAX    // 02 cfst.cf_mode
               " %14" PRIdMAX   // 03 cfst.cf_lmode
               " %14" PRIdMAX   // 04 cfst.cf_uid
               " %14" PRIdMAX   // 05 cfst.cf_gid
               " %18" PRIdMAX   // 06 cfst.cf_size
               " %14" PRIdMAX   // 07 cfst.cf_atime
               " %14" PRIdMAX   // 08 cfst.cf_mtime
               " %14" PRIdMAX   // 09 cfst.cf_ctime
               " %1" PRIdMAX    // 10 cfst.cf_makeholes
               " %14" PRIdMAX   // 11 cfst.cf_ino
               " %14" PRIdMAX   // 12 cfst.cf_nlink
               " %18" PRIdMAX,  // 13 cfst.cf_dev
               &d1, &d2, &d3, &d4, &d5, &d6, &d7, &d8, &d9, &d10, &d11, &d12, &d13);

        if (ret < 13)
        {
            Log(LOG_LEVEL_ERR, "Cannot read SYNCH reply from '%s', only %d/13 items parsed", conn->remoteip, ret );
            return -1;
        }

        cfst.cf_type = (FileType) d1;
        cfst.cf_mode = (mode_t) d2;
        cfst.cf_lmode = (mode_t) d3;
        cfst.cf_uid = (uid_t) d4;
        cfst.cf_gid = (gid_t) d5;
        cfst.cf_size = (off_t) d6;
        cfst.cf_atime = (time_t) d7;
        cfst.cf_mtime = (time_t) d8;
        cfst.cf_ctime = (time_t) d9;
        cfst.cf_makeholes = (char) d10;
        cfst.cf_ino = d11;
        cfst.cf_nlink = d12;
        cfst.cf_dev = (dev_t)d13;

        /* Use %?d here to avoid memory overflow attacks */

        memset(recvbuffer, 0, CF_BUFSIZE);

        if (ReceiveTransaction(conn->sd, recvbuffer, NULL) == -1)
        {
            return -1;
        }

        if (strlen(recvbuffer) > 3)
        {
            cfst.cf_readlink = xstrdup(recvbuffer + 3);
        }
        else
        {
            cfst.cf_readlink = NULL;
        }

        switch (cfst.cf_type)
        {
        case FILE_TYPE_REGULAR:
            cfst.cf_mode |= (mode_t) S_IFREG;
            break;
        case FILE_TYPE_DIR:
            cfst.cf_mode |= (mode_t) S_IFDIR;
            break;
        case FILE_TYPE_CHAR_:
            cfst.cf_mode |= (mode_t) S_IFCHR;
            break;
        case FILE_TYPE_FIFO:
            cfst.cf_mode |= (mode_t) S_IFIFO;
            break;
        case FILE_TYPE_SOCK:
            cfst.cf_mode |= (mode_t) S_IFSOCK;
            break;
        case FILE_TYPE_BLOCK:
            cfst.cf_mode |= (mode_t) S_IFBLK;
            break;
        case FILE_TYPE_LINK:
            cfst.cf_mode |= (mode_t) S_IFLNK;
            break;
        }

        cfst.cf_filename = xstrdup(file);
        cfst.cf_server = xstrdup(conn->this_server);
        cfst.cf_failed = false;

        if (cfst.cf_lmode != 0)
        {
            cfst.cf_lmode |= (mode_t) S_IFLNK;
        }

        NewClientCache(&cfst, conn);

        if ((cfst.cf_lmode != 0) && (strcmp(stattype, "link") == 0))
        {
            buf->st_mode = cfst.cf_lmode;
        }
        else
        {
            buf->st_mode = cfst.cf_mode;
        }

        buf->st_uid = cfst.cf_uid;
        buf->st_gid = cfst.cf_gid;
        buf->st_size = cfst.cf_size;
        buf->st_mtime = cfst.cf_mtime;
        buf->st_ctime = cfst.cf_ctime;
        buf->st_atime = cfst.cf_atime;
        buf->st_ino = cfst.cf_ino;
        buf->st_dev = cfst.cf_dev;
        buf->st_nlink = cfst.cf_nlink;

        return 0;
    }

    Log(LOG_LEVEL_ERR, "Transmission refused or failed statting '%s', got '%s'", file, recvbuffer);
    errno = EPERM;
    return -1;
}
コード例 #7
0
ファイル: client_protocol.c プロジェクト: jooooooon/core
int AuthenticateAgent(AgentConnection *conn, bool trust_key)
{
    char sendbuffer[CF_EXPANDSIZE], in[CF_BUFSIZE], *out, *decrypted_cchall;
    BIGNUM *nonce_challenge, *bn = NULL;
    unsigned long err;
    unsigned char digest[EVP_MAX_MD_SIZE];
    int encrypted_len, nonce_len = 0, len, session_size;
    bool implicitly_trust_server;
    char enterprise_field = 'c';
    RSA *server_pubkey = NULL;

    if ((PUBKEY == NULL) || (PRIVKEY == NULL))
    {
        Log(LOG_LEVEL_ERR, "No public/private key pair found at %s", PublicKeyFile(GetWorkDir()));
        return false;
    }

    enterprise_field = CfEnterpriseOptions();
    session_size = CfSessionKeySize(enterprise_field);

/* Generate a random challenge to authenticate the server */

    nonce_challenge = BN_new();
    if (nonce_challenge == NULL)
    {
        Log(LOG_LEVEL_ERR, "Cannot allocate BIGNUM structure for server challenge");
        return false;
    }

    BN_rand(nonce_challenge, CF_NONCELEN, 0, 0);
    nonce_len = BN_bn2mpi(nonce_challenge, in);

    if (FIPS_MODE)
    {
        HashString(in, nonce_len, digest, CF_DEFAULT_DIGEST);
    }
    else
    {
        HashString(in, nonce_len, digest, HASH_METHOD_MD5);
    }

/* We assume that the server bound to the remote socket is the official one i.e. = root's */

    if ((server_pubkey = HavePublicKeyByIP(conn->username, conn->remoteip)))
    {
        implicitly_trust_server = false;
        encrypted_len = RSA_size(server_pubkey);
    }
    else
    {
        implicitly_trust_server = true;
        encrypted_len = nonce_len;
    }

// Server pubkey is what we want to has as a unique ID

    snprintf(sendbuffer, sizeof(sendbuffer), "SAUTH %c %d %d %c", implicitly_trust_server ? 'n': 'y', encrypted_len,
             nonce_len, enterprise_field);

    out = xmalloc(encrypted_len);

    if (server_pubkey != NULL)
    {
        if (RSA_public_encrypt(nonce_len, in, out, server_pubkey, RSA_PKCS1_PADDING) <= 0)
        {
            err = ERR_get_error();
            Log(LOG_LEVEL_ERR, "Public encryption failed = %s", ERR_reason_error_string(err));
            free(out);
            RSA_free(server_pubkey);
            return false;
        }

        memcpy(sendbuffer + CF_RSA_PROTO_OFFSET, out, encrypted_len);
    }
    else
    {
        memcpy(sendbuffer + CF_RSA_PROTO_OFFSET, in, nonce_len);
    }

/* proposition C1 - Send challenge / nonce */

    SendTransaction(conn->sd, sendbuffer, CF_RSA_PROTO_OFFSET + encrypted_len, CF_DONE);

    BN_free(bn);
    BN_free(nonce_challenge);
    free(out);

    if (DEBUG)
    {
        RSA_print_fp(stdout, PUBKEY, 0);
    }

/*Send the public key - we don't know if server has it */
/* proposition C2 */

    memset(sendbuffer, 0, CF_EXPANDSIZE);
    len = BN_bn2mpi(PUBKEY->n, sendbuffer);
    SendTransaction(conn->sd, sendbuffer, len, CF_DONE);        /* No need to encrypt the public key ... */

/* proposition C3 */
    memset(sendbuffer, 0, CF_EXPANDSIZE);
    len = BN_bn2mpi(PUBKEY->e, sendbuffer);
    SendTransaction(conn->sd, sendbuffer, len, CF_DONE);

/* check reply about public key - server can break connection here */

/* proposition S1 */
    memset(in, 0, CF_BUFSIZE);

    if (ReceiveTransaction(conn->sd, in, NULL) == -1)
    {
        Log(LOG_LEVEL_ERR, "Protocol transaction broken off (1): %s", GetErrorStr());
        RSA_free(server_pubkey);
        return false;
    }

    if (BadProtoReply(in))
    {
        Log(LOG_LEVEL_ERR, "%s", in);
        RSA_free(server_pubkey);
        return false;
    }

/* Get challenge response - should be CF_DEFAULT_DIGEST of challenge */

/* proposition S2 */
    memset(in, 0, CF_BUFSIZE);

    if (ReceiveTransaction(conn->sd, in, NULL) == -1)
    {
        Log(LOG_LEVEL_ERR, "Protocol transaction broken off (2): %s", GetErrorStr());
        RSA_free(server_pubkey);
        return false;
    }

    if ((HashesMatch(digest, in, CF_DEFAULT_DIGEST)) || (HashesMatch(digest, in, HASH_METHOD_MD5)))  // Legacy
    {
        if (implicitly_trust_server == false)        /* challenge reply was correct */
        {
            Log(LOG_LEVEL_VERBOSE, ".....................[.h.a.i.l.].................................");
            Log(LOG_LEVEL_VERBOSE, "Strong authentication of server=%s connection confirmed", conn->this_server);
        }
        else
        {
            if (trust_key)
            {
                Log(LOG_LEVEL_VERBOSE, " -> Trusting server identity, promise to accept key from %s=%s", conn->this_server,
                      conn->remoteip);
            }
            else
            {
                Log(LOG_LEVEL_ERR, " !! Not authorized to trust the server=%s's public key (trustkey=false)",
                      conn->this_server);
                RSA_free(server_pubkey);
                return false;
            }
        }
    }
    else
    {
        Log(LOG_LEVEL_ERR, "Challenge response from server %s/%s was incorrect!", conn->this_server,
             conn->remoteip);
        RSA_free(server_pubkey);
        return false;
    }

/* Receive counter challenge from server */

/* proposition S3 */
    memset(in, 0, CF_BUFSIZE);
    encrypted_len = ReceiveTransaction(conn->sd, in, NULL);

    if (encrypted_len <= 0)
    {
        Log(LOG_LEVEL_ERR, "Protocol transaction sent illegal cipher length");
        RSA_free(server_pubkey);
        return false;
    }

    decrypted_cchall = xmalloc(encrypted_len);

    if (RSA_private_decrypt(encrypted_len, in, decrypted_cchall, PRIVKEY, RSA_PKCS1_PADDING) <= 0)
    {
        err = ERR_get_error();
        Log(LOG_LEVEL_ERR, "Private decrypt failed = %s, abandoning",
             ERR_reason_error_string(err));
        RSA_free(server_pubkey);
        return false;
    }

/* proposition C4 */
    if (FIPS_MODE)
    {
        HashString(decrypted_cchall, nonce_len, digest, CF_DEFAULT_DIGEST);
    }
    else
    {
        HashString(decrypted_cchall, nonce_len, digest, HASH_METHOD_MD5);
    }

    if (FIPS_MODE)
    {
        SendTransaction(conn->sd, digest, CF_DEFAULT_DIGEST_LEN, CF_DONE);
    }
    else
    {
        SendTransaction(conn->sd, digest, CF_MD5_LEN, CF_DONE);
    }

    free(decrypted_cchall);

/* If we don't have the server's public key, it will be sent */

    if (server_pubkey == NULL)
    {
        RSA *newkey = RSA_new();

        Log(LOG_LEVEL_VERBOSE, " -> Collecting public key from server!");

        /* proposition S4 - conditional */
        if ((len = ReceiveTransaction(conn->sd, in, NULL)) <= 0)
        {
            Log(LOG_LEVEL_ERR, "Protocol error in RSA authentation from IP %s", conn->this_server);
            return false;
        }

        if ((newkey->n = BN_mpi2bn(in, len, NULL)) == NULL)
        {
            err = ERR_get_error();
            Log(LOG_LEVEL_ERR, "Private key decrypt failed = %s", ERR_reason_error_string(err));
            RSA_free(newkey);
            return false;
        }

        /* proposition S5 - conditional */

        if ((len = ReceiveTransaction(conn->sd, in, NULL)) <= 0)
        {
            Log(LOG_LEVEL_INFO, "Protocol error in RSA authentation from IP %s",
                 conn->this_server);
            RSA_free(newkey);
            return false;
        }

        if ((newkey->e = BN_mpi2bn(in, len, NULL)) == NULL)
        {
            err = ERR_get_error();
            Log(LOG_LEVEL_ERR, "Public key decrypt failed = %s", ERR_reason_error_string(err));
            RSA_free(newkey);
            return false;
        }

        server_pubkey = RSAPublicKey_dup(newkey);
        RSA_free(newkey);
    }

/* proposition C5 */

    if (!SetSessionKey(conn))
    {
        Log(LOG_LEVEL_ERR, "Unable to set session key");
        return false;
    }

    if (conn->session_key == NULL)
    {
        Log(LOG_LEVEL_ERR, "A random session key could not be established");
        RSA_free(server_pubkey);
        return false;
    }

    encrypted_len = RSA_size(server_pubkey);

    out = xmalloc(encrypted_len);

    if (RSA_public_encrypt(session_size, conn->session_key, out, server_pubkey, RSA_PKCS1_PADDING) <= 0)
    {
        err = ERR_get_error();
        Log(LOG_LEVEL_ERR, "Public encryption failed = %s", ERR_reason_error_string(err));
        free(out);
        RSA_free(server_pubkey);
        return false;
    }

    SendTransaction(conn->sd, out, encrypted_len, CF_DONE);

    if (server_pubkey != NULL)
    {
        char buffer[EVP_MAX_MD_SIZE * 4];
        HashPubKey(server_pubkey, conn->digest, CF_DEFAULT_DIGEST);
        Log(LOG_LEVEL_VERBOSE, " -> Public key identity of host \"%s\" is \"%s\"", conn->remoteip,
              HashPrintSafe(CF_DEFAULT_DIGEST, conn->digest, buffer));
        SavePublicKey(conn->username, conn->remoteip, buffer, server_pubkey);       // FIXME: username is local
        LastSaw(conn->remoteip, conn->digest, LAST_SEEN_ROLE_CONNECT);
    }

    free(out);
    RSA_free(server_pubkey);

    return true;
}
コード例 #8
0
int AuthenticateAgent(AgentConnection *conn, Attributes attr, Promise *pp)
{
    char sendbuffer[CF_EXPANDSIZE], in[CF_BUFSIZE], *out, *decrypted_cchall;
    BIGNUM *nonce_challenge, *bn = NULL;
    unsigned long err;
    unsigned char digest[EVP_MAX_MD_SIZE];
    int encrypted_len, nonce_len = 0, len, session_size;
    char dont_implicitly_trust_server, enterprise_field = 'c';
    RSA *server_pubkey = NULL;

    if (PUBKEY == NULL || PRIVKEY == NULL)
    {
        CfOut(cf_error, "", "No public/private key pair found\n");
        return false;
    }

    enterprise_field = CfEnterpriseOptions();
    session_size = CfSessionKeySize(enterprise_field);

/* Generate a random challenge to authenticate the server */

    nonce_challenge = BN_new();
    BN_rand(nonce_challenge, CF_NONCELEN, 0, 0);
    nonce_len = BN_bn2mpi(nonce_challenge, in);

    if (FIPS_MODE)
    {
        HashString(in, nonce_len, digest, CF_DEFAULT_DIGEST);
    }
    else
    {
        HashString(in, nonce_len, digest, cf_md5);
    }

/* We assume that the server bound to the remote socket is the official one i.e. = root's */

    if ((server_pubkey = HavePublicKeyByIP(conn->username, conn->remoteip)))
    {
        dont_implicitly_trust_server = 'y';
        encrypted_len = RSA_size(server_pubkey);
    }
    else
    {
        dont_implicitly_trust_server = 'n';     /* have to trust server, since we can't verify id */
        encrypted_len = nonce_len;
    }

// Server pubkey is what we want to has as a unique ID

    snprintf(sendbuffer, sizeof(sendbuffer), "SAUTH %c %d %d %c", dont_implicitly_trust_server, encrypted_len,
             nonce_len, enterprise_field);

    out = xmalloc(encrypted_len);

    if (server_pubkey != NULL)
    {
        if (RSA_public_encrypt(nonce_len, in, out, server_pubkey, RSA_PKCS1_PADDING) <= 0)
        {
            err = ERR_get_error();
            cfPS(cf_error, CF_FAIL, "", pp, attr, "Public encryption failed = %s\n", ERR_reason_error_string(err));
            free(out);
            FreeRSAKey(server_pubkey);
            return false;
        }

        memcpy(sendbuffer + CF_RSA_PROTO_OFFSET, out, encrypted_len);
    }
    else
    {
        memcpy(sendbuffer + CF_RSA_PROTO_OFFSET, in, nonce_len);
    }

/* proposition C1 - Send challenge / nonce */

    SendTransaction(conn->sd, sendbuffer, CF_RSA_PROTO_OFFSET + encrypted_len, CF_DONE);

    BN_free(bn);
    BN_free(nonce_challenge);
    free(out);

    if (DEBUG)
    {
        RSA_print_fp(stdout, PUBKEY, 0);
    }

/*Send the public key - we don't know if server has it */
/* proposition C2 */

    memset(sendbuffer, 0, CF_EXPANDSIZE);
    len = BN_bn2mpi(PUBKEY->n, sendbuffer);
    SendTransaction(conn->sd, sendbuffer, len, CF_DONE);        /* No need to encrypt the public key ... */

/* proposition C3 */
    memset(sendbuffer, 0, CF_EXPANDSIZE);
    len = BN_bn2mpi(PUBKEY->e, sendbuffer);
    SendTransaction(conn->sd, sendbuffer, len, CF_DONE);

/* check reply about public key - server can break connection here */

/* proposition S1 */
    memset(in, 0, CF_BUFSIZE);

    if (ReceiveTransaction(conn->sd, in, NULL) == -1)
    {
        cfPS(cf_error, CF_INTERPT, "recv", pp, attr, "Protocol transaction broken off (1)");
        FreeRSAKey(server_pubkey);
        return false;
    }

    if (BadProtoReply(in))
    {
        CfOut(cf_error, "", "%s", in);
        FreeRSAKey(server_pubkey);
        return false;
    }

/* Get challenge response - should be CF_DEFAULT_DIGEST of challenge */

/* proposition S2 */
    memset(in, 0, CF_BUFSIZE);

    if (ReceiveTransaction(conn->sd, in, NULL) == -1)
    {
        cfPS(cf_error, CF_INTERPT, "recv", pp, attr, "Protocol transaction broken off (2)");
        FreeRSAKey(server_pubkey);
        return false;
    }

    if (HashesMatch(digest, in, CF_DEFAULT_DIGEST) || HashesMatch(digest, in, cf_md5))  // Legacy
    {
        if (dont_implicitly_trust_server == 'y')        /* challenge reply was correct */
        {
            CfOut(cf_verbose, "", ".....................[.h.a.i.l.].................................\n");
            CfOut(cf_verbose, "", "Strong authentication of server=%s connection confirmed\n", pp->this_server);
        }
        else
        {
            if (attr.copy.trustkey)
            {
                CfOut(cf_verbose, "", " -> Trusting server identity, promise to accept key from %s=%s", pp->this_server,
                      conn->remoteip);
            }
            else
            {
                CfOut(cf_error, "", " !! Not authorized to trust the server=%s's public key (trustkey=false)\n",
                      pp->this_server);
                PromiseRef(cf_verbose, pp);
                FreeRSAKey(server_pubkey);
                return false;
            }
        }
    }
    else
    {
        cfPS(cf_error, CF_INTERPT, "", pp, attr, "Challenge response from server %s/%s was incorrect!", pp->this_server,
             conn->remoteip);
        FreeRSAKey(server_pubkey);
        return false;
    }

/* Receive counter challenge from server */

    CfDebug("Receive counter challenge from server\n");

/* proposition S3 */
    memset(in, 0, CF_BUFSIZE);
    encrypted_len = ReceiveTransaction(conn->sd, in, NULL);

    if (encrypted_len <= 0)
    {
        CfOut(cf_error, "", "Protocol transaction sent illegal cipher length");
        FreeRSAKey(server_pubkey);
        return false;
    }

    decrypted_cchall = xmalloc(encrypted_len);

    if (RSA_private_decrypt(encrypted_len, in, decrypted_cchall, PRIVKEY, RSA_PKCS1_PADDING) <= 0)
    {
        err = ERR_get_error();
        cfPS(cf_error, CF_INTERPT, "", pp, attr, "Private decrypt failed = %s, abandoning\n",
             ERR_reason_error_string(err));
        FreeRSAKey(server_pubkey);
        return false;
    }

/* proposition C4 */
    if (FIPS_MODE)
    {
        HashString(decrypted_cchall, nonce_len, digest, CF_DEFAULT_DIGEST);
    }
    else
    {
        HashString(decrypted_cchall, nonce_len, digest, cf_md5);
    }

    CfDebug("Replying to counter challenge with hash\n");

    if (FIPS_MODE)
    {
        SendTransaction(conn->sd, digest, CF_DEFAULT_DIGEST_LEN, CF_DONE);
    }
    else
    {
        SendTransaction(conn->sd, digest, CF_MD5_LEN, CF_DONE);
    }

    free(decrypted_cchall);

/* If we don't have the server's public key, it will be sent */

    if (server_pubkey == NULL)
    {
        RSA *newkey = RSA_new();

        CfOut(cf_verbose, "", " -> Collecting public key from server!\n");

        /* proposition S4 - conditional */
        if ((len = ReceiveTransaction(conn->sd, in, NULL)) <= 0)
        {
            CfOut(cf_error, "", "Protocol error in RSA authentation from IP %s\n", pp->this_server);
            return false;
        }

        if ((newkey->n = BN_mpi2bn(in, len, NULL)) == NULL)
        {
            err = ERR_get_error();
            cfPS(cf_error, CF_INTERPT, "", pp, attr, "Private key decrypt failed = %s\n", ERR_reason_error_string(err));
            FreeRSAKey(newkey);
            return false;
        }

        /* proposition S5 - conditional */

        if ((len = ReceiveTransaction(conn->sd, in, NULL)) <= 0)
        {
            cfPS(cf_inform, CF_INTERPT, "", pp, attr, "Protocol error in RSA authentation from IP %s\n",
                 pp->this_server);
            FreeRSAKey(newkey);
            return false;
        }

        if ((newkey->e = BN_mpi2bn(in, len, NULL)) == NULL)
        {
            err = ERR_get_error();
            cfPS(cf_error, CF_INTERPT, "", pp, attr, "Public key decrypt failed = %s\n", ERR_reason_error_string(err));
            FreeRSAKey(newkey);
            return false;
        }

        server_pubkey = RSAPublicKey_dup(newkey);
        FreeRSAKey(newkey);
    }

/* proposition C5 */

    SetSessionKey(conn);

    if (conn->session_key == NULL)
    {
        CfOut(cf_error, "", "A random session key could not be established");
        FreeRSAKey(server_pubkey);
        return false;
    }

    encrypted_len = RSA_size(server_pubkey);

    CfDebug("Encrypt %d bytes of session key into %d RSA bytes\n", session_size, encrypted_len);

    out = xmalloc(encrypted_len);

    if (RSA_public_encrypt(session_size, conn->session_key, out, server_pubkey, RSA_PKCS1_PADDING) <= 0)
    {
        err = ERR_get_error();
        cfPS(cf_error, CF_INTERPT, "", pp, attr, "Public encryption failed = %s\n", ERR_reason_error_string(err));
        free(out);
        FreeRSAKey(server_pubkey);
        return false;
    }

    SendTransaction(conn->sd, out, encrypted_len, CF_DONE);

    if (server_pubkey != NULL)
    {
        HashPubKey(server_pubkey, conn->digest, CF_DEFAULT_DIGEST);
        CfOut(cf_verbose, "", " -> Public key identity of host \"%s\" is \"%s\"", conn->remoteip,
              HashPrint(CF_DEFAULT_DIGEST, conn->digest));
        SavePublicKey(conn->username, conn->remoteip, HashPrint(CF_DEFAULT_DIGEST, conn->digest), server_pubkey);       // FIXME: username is local
        LastSaw(conn->remoteip, conn->digest, cf_connect);
    }

    free(out);
    FreeRSAKey(server_pubkey);
    return true;
}
コード例 #9
0
ファイル: client_code.c プロジェクト: amousset/core
/* Returning NULL (an empty list) does not mean empty directory but ERROR,
 * since every directory has to contain at least . and .. */
Item *RemoteDirList(const char *dirname, bool encrypt, AgentConnection *conn)
{
    char sendbuffer[CF_BUFSIZE];
    char recvbuffer[CF_BUFSIZE];
    char in[CF_BUFSIZE];
    char out[CF_BUFSIZE];
    int cipherlen = 0, tosend;

    if (strlen(dirname) > CF_BUFSIZE - 20)
    {
        Log(LOG_LEVEL_ERR, "Directory name too long");
        return NULL;
    }

    /* We encrypt only for CLASSIC protocol. The TLS protocol is always over
     * encrypted layer, so it does not support encrypted (S*) commands. */
    encrypt = encrypt && conn->conn_info->protocol == CF_PROTOCOL_CLASSIC;

    if (encrypt)
    {
        if (conn->session_key == NULL)
        {
            Log(LOG_LEVEL_ERR, "Cannot do encrypted copy without keys (use cf-key)");
            return NULL;
        }

        snprintf(in, CF_BUFSIZE, "OPENDIR %s", dirname);
        cipherlen = EncryptString(conn->encryption_type, in, out, conn->session_key, strlen(in) + 1);
        snprintf(sendbuffer, CF_BUFSIZE - 1, "SOPENDIR %d", cipherlen);
        memcpy(sendbuffer + CF_PROTO_OFFSET, out, cipherlen);
        tosend = cipherlen + CF_PROTO_OFFSET;
    }
    else
    {
        snprintf(sendbuffer, CF_BUFSIZE, "OPENDIR %s", dirname);
        tosend = strlen(sendbuffer);
    }

    if (SendTransaction(conn->conn_info, sendbuffer, tosend, CF_DONE) == -1)
    {
        return NULL;
    }

    Item *start = NULL, *end = NULL;                  /* NULL == empty list */
    while (true)
    {
        /* TODO check the CF_MORE flag, no need for CFD_TERMINATOR. */
        int nbytes = ReceiveTransaction(conn->conn_info, recvbuffer, NULL);

        /* If recv error or socket closed before receiving CFD_TERMINATOR. */
        if (nbytes == -1 || nbytes == 0)
        {
            /* TODO mark connection in the cache as closed. */
            goto err;
        }

        if (recvbuffer[0] == '\0')
        {
            Log(LOG_LEVEL_ERR,
                "Empty%s server packet when listing directory '%s'!",
                (start == NULL) ? " first" : "",
                dirname);
            goto err;
        }

        if (encrypt)
        {
            memcpy(in, recvbuffer, nbytes);
            DecryptString(conn->encryption_type, in, recvbuffer,
                          conn->session_key, nbytes);
        }

        if (FailedProtoReply(recvbuffer))
        {
            Log(LOG_LEVEL_INFO, "Network access to '%s:%s' denied", conn->this_server, dirname);
            goto err;
        }

        if (BadProtoReply(recvbuffer))
        {
            Log(LOG_LEVEL_INFO, "%s", recvbuffer + strlen("BAD: "));
            goto err;
        }

        /* Double '\0' means end of packet. */
        for (char *sp = recvbuffer; *sp != '\0'; sp += strlen(sp) + 1)
        {
            if (strcmp(sp, CFD_TERMINATOR) == 0)      /* end of all packets */
            {
                return start;
            }

            Item *ip = xcalloc(1, sizeof(Item));
            ip->name = (char *) AllocateDirentForFilename(sp);

            if (start == NULL)  /* First element */
            {
                start = ip;
                end = ip;
            }
            else
            {
                end->next = ip;
                end = ip;
            }
        }
    }

    return start;

  err:                                                         /* free list */
    for (Item *ip = start; ip != NULL; ip = start)
    {
        start = ip->next;
        free(ip->name);
        free(ip);
    }

    return NULL;
}