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__ 91b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSRequest" 92b967cddfSBarry Smith /* 93b967cddfSBarry Smith PetscHTTPSRequest - Send a request to an HTTPS server 94b967cddfSBarry Smith 95b967cddfSBarry Smith Input Parameters: 96b967cddfSBarry Smith + type - either "POST" or "GET" 97*93e1d32fSBarry Smith . url - URL of request host/path 98b967cddfSBarry Smith . header - additional header information, may be NULL 99b967cddfSBarry Smith . ctype - data type of body, for example application/json 100b967cddfSBarry Smith . body - data to send to server 101b967cddfSBarry Smith . ssl - obtained with PetscHTTPSConnect() 102b967cddfSBarry Smith - buffsize - size of buffer 103b967cddfSBarry Smith 104b967cddfSBarry Smith Output Parameter: 105b967cddfSBarry Smith . buff - everything returned from server 106b967cddfSBarry Smith */ 1070efc6a03SBarry 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) 108b967cddfSBarry Smith { 109b967cddfSBarry Smith char *request=0; 110*93e1d32fSBarry Smith char contentlength[40],contenttype[80],*path,*host; 111b967cddfSBarry Smith int r; 112*93e1d32fSBarry Smith size_t request_len,len,headlen,bodylen,contentlen,pathlen,hostlen,typelen,contenttypelen = 0; 113b967cddfSBarry Smith PetscErrorCode ierr; 114b967cddfSBarry Smith PetscBool flg; 115b967cddfSBarry Smith 116b967cddfSBarry Smith PetscFunctionBegin; 117*93e1d32fSBarry Smith ierr = PetscStrallocpy(url,&host);CHKERRQ(ierr); 118*93e1d32fSBarry Smith ierr = PetscStrchr(host,'/',&path);CHKERRQ(ierr); 119*93e1d32fSBarry Smith if (!path) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"url must contain / it is %s",url); 120*93e1d32fSBarry Smith *path = NULL; 121*93e1d32fSBarry Smith ierr = PetscStrlen(host,&hostlen);CHKERRQ(ierr); 122*93e1d32fSBarry Smith 123*93e1d32fSBarry Smith ierr = PetscStrchr(url,'/',&path);CHKERRQ(ierr); 124*93e1d32fSBarry Smith ierr = PetscStrlen(path,&pathlen);CHKERRQ(ierr); 125*93e1d32fSBarry Smith 126b967cddfSBarry Smith if (header) { 127b967cddfSBarry Smith ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 128b967cddfSBarry Smith if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 129b967cddfSBarry Smith } 130b967cddfSBarry Smith 131b967cddfSBarry Smith ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 132b967cddfSBarry Smith if (ctype) { 133b967cddfSBarry Smith ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 134b967cddfSBarry Smith ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 135b967cddfSBarry Smith } 136b967cddfSBarry Smith ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 137b967cddfSBarry Smith ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 138b967cddfSBarry Smith ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 139b967cddfSBarry Smith ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 140b967cddfSBarry Smith 141b967cddfSBarry Smith /* Now construct our HTTP request */ 142*93e1d32fSBarry Smith request_len = typelen + 1 + pathlen + hostlen + 100 + headlen + contenttypelen + contentlen + bodylen + 1; 143fe278a28SBarry Smith ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 144b967cddfSBarry Smith ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 145b967cddfSBarry Smith ierr = PetscStrcat(request," ");CHKERRQ(ierr); 146*93e1d32fSBarry Smith ierr = PetscStrcat(request,path);CHKERRQ(ierr); 147*93e1d32fSBarry Smith ierr = PetscStrcat(request," HTTP/1.1\r\nHost: ");CHKERRQ(ierr); 148*93e1d32fSBarry Smith ierr = PetscStrcat(request,host);CHKERRQ(ierr); 149*93e1d32fSBarry Smith ierr = PetscFree(host);CHKERRQ(ierr); 150*93e1d32fSBarry Smith ierr = PetscStrcat(request,"\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 151b967cddfSBarry Smith ierr = PetscStrcat(request,header);CHKERRQ(ierr); 152b967cddfSBarry Smith if (ctype) { 153b967cddfSBarry Smith ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 154b967cddfSBarry Smith } 155b967cddfSBarry Smith ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 156b967cddfSBarry Smith ierr = PetscStrcat(request,body);CHKERRQ(ierr); 157b967cddfSBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 158b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 159b967cddfSBarry Smith 160b967cddfSBarry Smith r = SSL_write(ssl,request,request_len); 161b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 162b967cddfSBarry Smith case SSL_ERROR_NONE: 163b967cddfSBarry Smith if (request_len != r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 164b967cddfSBarry Smith break; 165b967cddfSBarry Smith default: 166b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 167b967cddfSBarry Smith } 168b967cddfSBarry Smith 169b967cddfSBarry Smith /* Now read the server's response, assuming that it's terminated by a close */ 170b967cddfSBarry Smith r = SSL_read(ssl,buff,(int)buffsize); 171b967cddfSBarry Smith len = r; 172b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 173b967cddfSBarry Smith case SSL_ERROR_NONE: 174b967cddfSBarry Smith break; 175b967cddfSBarry Smith case SSL_ERROR_ZERO_RETURN: 176b967cddfSBarry Smith SSL_shutdown(ssl); /* ignore shutdown error message */ 177b967cddfSBarry Smith break; 178b967cddfSBarry Smith case SSL_ERROR_SYSCALL: 179b967cddfSBarry Smith break; 180b967cddfSBarry Smith default: 181b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 182b967cddfSBarry Smith } 183b967cddfSBarry Smith buff[len] = 0; /* null terminate string */ 184b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 185b967cddfSBarry Smith 186b967cddfSBarry Smith SSL_free(ssl); 187b967cddfSBarry Smith ierr = PetscFree(request);CHKERRQ(ierr); 188b967cddfSBarry Smith PetscFunctionReturn(0); 189b967cddfSBarry Smith } 190b967cddfSBarry Smith 191b967cddfSBarry Smith #undef __FUNCT__ 192b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSConnect" 193b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 194b967cddfSBarry Smith { 195b967cddfSBarry Smith BIO *sbio; 196b967cddfSBarry Smith PetscErrorCode ierr; 197b967cddfSBarry Smith 198b967cddfSBarry Smith PetscFunctionBegin; 199b967cddfSBarry Smith /* Connect the TCP socket*/ 200b967cddfSBarry Smith ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 201b967cddfSBarry Smith 202b967cddfSBarry Smith /* Connect the SSL socket */ 203b967cddfSBarry Smith *ssl = SSL_new(ctx); 204b967cddfSBarry Smith sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 205b967cddfSBarry Smith SSL_set_bio(*ssl,sbio,sbio); 206b967cddfSBarry Smith if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 207b967cddfSBarry Smith PetscFunctionReturn(0); 208b967cddfSBarry Smith } 209b967cddfSBarry Smith 210