1b967cddfSBarry Smith 20efc6a03SBarry Smith #include <petscwebclient.h> 3b967cddfSBarry Smith 4b967cddfSBarry Smith static BIO *bio_err = NULL; 5b967cddfSBarry Smith 6b967cddfSBarry Smith #define PASSWORD "password" 7b967cddfSBarry Smith 84a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE) 9b967cddfSBarry Smith static int password_cb(char *buf,int num, int rwflag,void *userdata) 10b967cddfSBarry Smith { 11b967cddfSBarry Smith if (num < strlen(PASSWORD)+1) return(0); 12b967cddfSBarry Smith strcpy(buf,PASSWORD); 13b967cddfSBarry Smith return(strlen(PASSWORD)); 14b967cddfSBarry Smith } 15b967cddfSBarry Smith #endif 16b967cddfSBarry Smith 17b967cddfSBarry Smith static void sigpipe_handle(int x) 18b967cddfSBarry Smith { 19b967cddfSBarry Smith } 20b967cddfSBarry Smith 21b967cddfSBarry Smith #undef __FUNCT__ 22b967cddfSBarry Smith #define __FUNCT__ "PetscSSLInitializeContext" 23b967cddfSBarry Smith /* 24b967cddfSBarry Smith PetscSSLInitializeContext - Set up an SSL context suitable for initiating HTTPS requests. 25b967cddfSBarry Smith 264a285bdaSBarry Smith If built with PETSC_USE_SSL_CERTIFICATE requires the user have created a self-signed certificate with 27b967cddfSBarry Smith 28b967cddfSBarry Smith $ ./CA.pl -newcert (using the passphrase of password) 29b967cddfSBarry Smith $ cat newkey.pem newcert.pem > sslclient.pem 30b967cddfSBarry Smith 31b967cddfSBarry Smith and put the resulting file in either the current directory (with the application) or in the home directory. This seems kind of 32b967cddfSBarry Smith silly but it was all I could figure out. 33b967cddfSBarry Smith 34b967cddfSBarry Smith */ 35b967cddfSBarry Smith PetscErrorCode PetscSSLInitializeContext(SSL_CTX **octx) 36b967cddfSBarry Smith { 37b967cddfSBarry Smith SSL_METHOD *meth; 38b967cddfSBarry Smith SSL_CTX *ctx; 394a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE) 40b967cddfSBarry Smith char keyfile[PETSC_MAX_PATH_LEN]; 41b967cddfSBarry Smith PetscBool exists; 42b967cddfSBarry Smith PetscErrorCode ierr; 43b967cddfSBarry Smith #endif 44b967cddfSBarry Smith 45b967cddfSBarry Smith PetscFunctionBegin; 46b967cddfSBarry Smith if (!bio_err){ 47b967cddfSBarry Smith SSL_library_init(); 48b967cddfSBarry Smith SSL_load_error_strings(); 49b967cddfSBarry Smith bio_err = BIO_new_fp(stderr,BIO_NOCLOSE); 50b967cddfSBarry Smith } 51b967cddfSBarry Smith 52b967cddfSBarry Smith /* Set up a SIGPIPE handler */ 53b967cddfSBarry Smith signal(SIGPIPE,sigpipe_handle); 54b967cddfSBarry Smith 55b967cddfSBarry Smith meth = SSLv23_method(); 56b967cddfSBarry Smith ctx = SSL_CTX_new(meth); 57b967cddfSBarry Smith 584a285bdaSBarry Smith #if defined(PETSC_USE_SSL_CERTIFICATE) 59b967cddfSBarry Smith /* Locate keyfile */ 60b967cddfSBarry Smith ierr = PetscStrcpy(keyfile,"sslclient.pem");CHKERRQ(ierr); 61b967cddfSBarry Smith ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 62b967cddfSBarry Smith if (!exists) { 63b967cddfSBarry Smith ierr = PetscGetHomeDirectory(keyfile,PETSC_MAX_PATH_LEN);CHKERRQ(ierr); 64b967cddfSBarry Smith ierr = PetscStrcat(keyfile,"/");CHKERRQ(ierr); 65b967cddfSBarry Smith ierr = PetscStrcat(keyfile,"sslclient.pem");CHKERRQ(ierr); 66b967cddfSBarry Smith ierr = PetscTestFile(keyfile,'r',&exists);CHKERRQ(ierr); 67b967cddfSBarry Smith if (!exists) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Unable to locate sslclient.pem file in current directory or home directory"); 68b967cddfSBarry Smith } 69b967cddfSBarry Smith 70b967cddfSBarry Smith /* Load our keys and certificates*/ 71b967cddfSBarry Smith if (!(SSL_CTX_use_certificate_chain_file(ctx,keyfile))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read certificate file"); 72b967cddfSBarry Smith 73b967cddfSBarry Smith SSL_CTX_set_default_passwd_cb(ctx,password_cb); 74b967cddfSBarry Smith if (!(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM))) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Cannot read key file"); 75b967cddfSBarry Smith #endif 76b967cddfSBarry Smith 77b967cddfSBarry Smith *octx = ctx; 78b967cddfSBarry Smith PetscFunctionReturn(0); 79b967cddfSBarry Smith } 80b967cddfSBarry Smith 81b967cddfSBarry Smith #undef __FUNCT__ 82b967cddfSBarry Smith #define __FUNCT__ "PetscSSLDestroyContext" 83b967cddfSBarry Smith PetscErrorCode PetscSSLDestroyContext(SSL_CTX *ctx) 84b967cddfSBarry Smith { 85b967cddfSBarry Smith PetscFunctionBegin; 86b967cddfSBarry Smith SSL_CTX_free(ctx); 87b967cddfSBarry Smith PetscFunctionReturn(0); 88b967cddfSBarry Smith } 89b967cddfSBarry Smith 90b967cddfSBarry Smith #undef __FUNCT__ 91*04102261SBarry Smith #define __FUNCT__ "PetscHTTPBuildRequest" 92*04102261SBarry Smith PetscErrorCode PetscHTTPBuildRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],char **outrequest) 93b967cddfSBarry Smith { 94b967cddfSBarry Smith char *request=0; 9593e1d32fSBarry Smith char contentlength[40],contenttype[80],*path,*host; 96b967cddfSBarry Smith int r; 9793e1d32fSBarry Smith size_t request_len,len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0; 98b967cddfSBarry Smith PetscErrorCode ierr; 99b967cddfSBarry Smith PetscBool flg; 100b967cddfSBarry Smith 101b967cddfSBarry Smith PetscFunctionBegin; 10293e1d32fSBarry Smith ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr); 10393e1d32fSBarry Smith ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr); 10493e1d32fSBarry Smith if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url); 10593e1d32fSBarry Smith *path = NULL; 10693e1d32fSBarry Smith ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr); 10793e1d32fSBarry Smith 10893e1d32fSBarry Smith ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr); 10993e1d32fSBarry Smith ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr); 11093e1d32fSBarry Smith 111b967cddfSBarry Smith if (header) { 112b967cddfSBarry Smith ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 113b967cddfSBarry Smith if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 114b967cddfSBarry Smith } 115b967cddfSBarry Smith 116b967cddfSBarry Smith ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 117b967cddfSBarry Smith if (ctype) { 118b967cddfSBarry Smith ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 119b967cddfSBarry Smith ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 120b967cddfSBarry Smith } 121b967cddfSBarry Smith ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 122b967cddfSBarry Smith ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 123b967cddfSBarry Smith ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 124b967cddfSBarry Smith ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 125b967cddfSBarry Smith 126b967cddfSBarry Smith /* Now construct our HTTP request */ 12793e1d32fSBarry Smith request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1; 128fe278a28SBarry Smith ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 129b967cddfSBarry Smith ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 130b967cddfSBarry Smith ierr = PetscStrcat(request," ");CHKERRQ(ierr); 13193e1d32fSBarry Smith ierr = PetscStrcat(request,path);CHKERRQ(ierr); 13293e1d32fSBarry Smith ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr); 13393e1d32fSBarry Smith ierr = PetscStrcat(request,host);CHKERRQ(ierr); 13493e1d32fSBarry Smith ierr = PetscFree(host);CHKERRQ(ierr); 13593e1d32fSBarry Smith ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 136b967cddfSBarry Smith ierr = PetscStrcat(request,header);CHKERRQ(ierr); 137b967cddfSBarry Smith if (ctype) { 138b967cddfSBarry Smith ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 139b967cddfSBarry Smith } 140b967cddfSBarry Smith ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 141b967cddfSBarry Smith ierr = PetscStrcat(request,body);CHKERRQ(ierr); 142b967cddfSBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 143b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 144b967cddfSBarry Smith 145*04102261SBarry Smith *outrequest = request; 146*04102261SBarry Smith PetscFunctionReturn(0); 147*04102261SBarry Smith } 148*04102261SBarry Smith 149*04102261SBarry Smith 150*04102261SBarry Smith #undef __FUNCT__ 151*04102261SBarry Smith #define __FUNCT__ "PetscHTTPSRequest" 152*04102261SBarry Smith /* 153*04102261SBarry Smith PetscHTTPSRequest - Send a request to an HTTPS server 154*04102261SBarry Smith 155*04102261SBarry Smith Input Parameters: 156*04102261SBarry Smith + type - either "POST" or "GET" 157*04102261SBarry Smith . url - URL of request host/path 158*04102261SBarry Smith . header - additional header information, may be NULL 159*04102261SBarry Smith . ctype - data type of body, for example application/json 160*04102261SBarry Smith . body - data to send to server 161*04102261SBarry Smith . ssl - obtained with PetscHTTPSConnect() 162*04102261SBarry Smith - buffsize - size of buffer 163*04102261SBarry Smith 164*04102261SBarry Smith Output Parameter: 165*04102261SBarry Smith . buff - everything returned from server 166*04102261SBarry Smith */ 167*04102261SBarry Smith PetscErrorCode PetscHTTPSRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],SSL *ssl,char buff[],size_t buffsize) 168*04102261SBarry Smith { 169*04102261SBarry Smith char *request; 170*04102261SBarry Smith int r; 171*04102261SBarry Smith size_t request_len,len; 172*04102261SBarry Smith PetscErrorCode ierr; 173*04102261SBarry Smith 174*04102261SBarry Smith PetscFunctionBegin; 175*04102261SBarry Smith ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 176*04102261SBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 177*04102261SBarry Smith 178b967cddfSBarry Smith r = SSL_write(ssl,request,request_len); 179b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 180b967cddfSBarry Smith case SSL_ERROR_NONE: 181b967cddfSBarry Smith if (request_len != r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 182b967cddfSBarry Smith break; 183b967cddfSBarry Smith default: 184b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 185b967cddfSBarry Smith } 186b967cddfSBarry Smith 187b967cddfSBarry Smith /* Now read the server's response, assuming that it's terminated by a close */ 188b967cddfSBarry Smith r = SSL_read(ssl,buff,(int)buffsize); 189b967cddfSBarry Smith len = r; 190b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 191b967cddfSBarry Smith case SSL_ERROR_NONE: 192b967cddfSBarry Smith break; 193b967cddfSBarry Smith case SSL_ERROR_ZERO_RETURN: 194b967cddfSBarry Smith SSL_shutdown(ssl); /* ignore shutdown error message */ 195b967cddfSBarry Smith break; 196b967cddfSBarry Smith case SSL_ERROR_SYSCALL: 197b967cddfSBarry Smith break; 198b967cddfSBarry Smith default: 199b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 200b967cddfSBarry Smith } 201b967cddfSBarry Smith buff[len] = 0; /* null terminate string */ 202b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 203b967cddfSBarry Smith 204b967cddfSBarry Smith SSL_free(ssl); 205b967cddfSBarry Smith ierr = PetscFree(request);CHKERRQ(ierr); 206b967cddfSBarry Smith PetscFunctionReturn(0); 207b967cddfSBarry Smith } 208b967cddfSBarry Smith 209b967cddfSBarry Smith #undef __FUNCT__ 210*04102261SBarry Smith #define __FUNCT__ "PetscHTTPRequest" 211*04102261SBarry Smith /* 212*04102261SBarry Smith PetscHTTPRequest - Send a request to an HTTP server 213*04102261SBarry Smith 214*04102261SBarry Smith Input Parameters: 215*04102261SBarry Smith + type - either "POST" or "GET" 216*04102261SBarry Smith . url - URL of request host/path 217*04102261SBarry Smith . header - additional header information, may be NULL 218*04102261SBarry Smith . ctype - data type of body, for example application/json 219*04102261SBarry Smith . body - data to send to server 220*04102261SBarry Smith . sock - obtained with PetscOpenSocket() 221*04102261SBarry Smith - buffsize - size of buffer 222*04102261SBarry Smith 223*04102261SBarry Smith Output Parameter: 224*04102261SBarry Smith . buff - everything returned from server 225*04102261SBarry Smith */ 226*04102261SBarry Smith PetscErrorCode PetscHTTPRequest(const char type[],const char url[],const char header[],const char ctype[],const char body[],int sock,char buff[],size_t buffsize) 227*04102261SBarry Smith { 228*04102261SBarry Smith char *request; 229*04102261SBarry Smith size_t request_len; 230*04102261SBarry Smith PetscErrorCode ierr; 231*04102261SBarry Smith 232*04102261SBarry Smith PetscFunctionBegin; 233*04102261SBarry Smith ierr = PetscHTTPBuildRequest(type,url,header,ctype,body,&request);CHKERRQ(ierr); 234*04102261SBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 235*04102261SBarry Smith 236*04102261SBarry Smith ierr = PetscBinaryWrite(sock,request,request_len,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr); 237*04102261SBarry Smith ierr = PetscFree(request);CHKERRQ(ierr); 238*04102261SBarry Smith PetscBinaryRead(sock,buff,buffsize,PETSC_CHAR); 239*04102261SBarry Smith buff[buffsize-1] = 0; 240*04102261SBarry Smith ierr = PetscInfo1(NULL,"HTTP result follows: \n%s\n",buff);CHKERRQ(ierr); 241*04102261SBarry Smith PetscFunctionReturn(0); 242*04102261SBarry Smith } 243*04102261SBarry Smith 244*04102261SBarry Smith 245*04102261SBarry Smith #undef __FUNCT__ 246b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSConnect" 247b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 248b967cddfSBarry Smith { 249b967cddfSBarry Smith BIO *sbio; 250b967cddfSBarry Smith PetscErrorCode ierr; 251b967cddfSBarry Smith 252b967cddfSBarry Smith PetscFunctionBegin; 253b967cddfSBarry Smith /* Connect the TCP socket*/ 254b967cddfSBarry Smith ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 255b967cddfSBarry Smith 256b967cddfSBarry Smith /* Connect the SSL socket */ 257b967cddfSBarry Smith *ssl = SSL_new(ctx); 258b967cddfSBarry Smith sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 259b967cddfSBarry Smith SSL_set_bio(*ssl,sbio,sbio); 260b967cddfSBarry Smith if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 261b967cddfSBarry Smith PetscFunctionReturn(0); 262b967cddfSBarry Smith } 263b967cddfSBarry Smith 264