1b967cddfSBarry Smith 2*0efc6a03SBarry Smith #include <petscwebclient.h> 3b967cddfSBarry Smith 4b967cddfSBarry Smith static BIO *bio_err = NULL; 5b967cddfSBarry Smith 6b967cddfSBarry Smith #define PASSWORD "password" 7b967cddfSBarry Smith 8b967cddfSBarry Smith #if defined(PETSC_USE_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 26b967cddfSBarry Smith If built with PETSC_USE_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; 39b967cddfSBarry Smith #if defined(PETSC_USE_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 58b967cddfSBarry Smith #if defined(PETSC_USE_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" 97b967cddfSBarry Smith . url - complete URL of request including https:// 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 */ 107*0efc6a03SBarry 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; 110b967cddfSBarry Smith char contentlength[40],contenttype[80]; 111b967cddfSBarry Smith int r; 112b967cddfSBarry Smith size_t request_len,len,headlen,bodylen,contentlen,urllen,typelen,contenttypelen = 0; 113b967cddfSBarry Smith PetscErrorCode ierr; 114b967cddfSBarry Smith PetscBool flg; 115b967cddfSBarry Smith 116b967cddfSBarry Smith PetscFunctionBegin; 117b967cddfSBarry Smith ierr = PetscStrbeginswith(url,"https://",&flg);CHKERRQ(ierr); 118b967cddfSBarry Smith if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"URL must begin with https://"); 119b967cddfSBarry Smith if (header) { 120b967cddfSBarry Smith ierr = PetscStrendswith(header,"\r\n",&flg);CHKERRQ(ierr); 121b967cddfSBarry Smith if (!flg) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"header must end with \\r\\n"); 122b967cddfSBarry Smith } 123b967cddfSBarry Smith 124b967cddfSBarry Smith ierr = PetscStrlen(type,&typelen);CHKERRQ(ierr); 125b967cddfSBarry Smith ierr = PetscStrlen(url,&urllen);CHKERRQ(ierr); 126b967cddfSBarry Smith if (ctype) { 127b967cddfSBarry Smith ierr = PetscSNPrintf(contenttype,80,"Content-Type: %s\r\n",ctype);CHKERRQ(ierr); 128b967cddfSBarry Smith ierr = PetscStrlen(contenttype,&contenttypelen);CHKERRQ(ierr); 129b967cddfSBarry Smith } 130b967cddfSBarry Smith ierr = PetscStrlen(header,&headlen);CHKERRQ(ierr); 131b967cddfSBarry Smith ierr = PetscStrlen(body,&bodylen);CHKERRQ(ierr); 132b967cddfSBarry Smith ierr = PetscSNPrintf(contentlength,40,"Content-Length: %d\r\n\r\n",(int)bodylen);CHKERRQ(ierr); 133b967cddfSBarry Smith ierr = PetscStrlen(contentlength,&contentlen);CHKERRQ(ierr); 134b967cddfSBarry Smith 135b967cddfSBarry Smith /* Now construct our HTTP request */ 136b967cddfSBarry Smith request_len = typelen + 1 + urllen + 35 + headlen + contenttypelen + contentlen + bodylen + 1; 137fe278a28SBarry Smith ierr = PetscMalloc1(request_len,&request);CHKERRQ(ierr); 138b967cddfSBarry Smith ierr = PetscStrcpy(request,type);CHKERRQ(ierr); 139b967cddfSBarry Smith ierr = PetscStrcat(request," ");CHKERRQ(ierr); 140b967cddfSBarry Smith ierr = PetscStrcat(request,url);CHKERRQ(ierr); 141b967cddfSBarry Smith ierr = PetscStrcat(request," HTTP/1.1\r\nUser-Agent:PETScClient\r\n");CHKERRQ(ierr); 142b967cddfSBarry Smith ierr = PetscStrcat(request,header);CHKERRQ(ierr); 143b967cddfSBarry Smith if (ctype) { 144b967cddfSBarry Smith ierr = PetscStrcat(request,contenttype);CHKERRQ(ierr); 145b967cddfSBarry Smith } 146b967cddfSBarry Smith ierr = PetscStrcat(request,contentlength);CHKERRQ(ierr); 147b967cddfSBarry Smith ierr = PetscStrcat(request,body);CHKERRQ(ierr); 148b967cddfSBarry Smith ierr = PetscStrlen(request,&request_len);CHKERRQ(ierr); 149b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS request follows: \n%s\n",request);CHKERRQ(ierr); 150b967cddfSBarry Smith 151b967cddfSBarry Smith r = SSL_write(ssl,request,request_len); 152b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 153b967cddfSBarry Smith case SSL_ERROR_NONE: 154b967cddfSBarry Smith if (request_len != r) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Incomplete write to SSL socket"); 155b967cddfSBarry Smith break; 156b967cddfSBarry Smith default: 157b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL socket write problem"); 158b967cddfSBarry Smith } 159b967cddfSBarry Smith 160b967cddfSBarry Smith /* Now read the server's response, assuming that it's terminated by a close */ 161b967cddfSBarry Smith r = SSL_read(ssl,buff,(int)buffsize); 162b967cddfSBarry Smith len = r; 163b967cddfSBarry Smith switch (SSL_get_error(ssl,r)){ 164b967cddfSBarry Smith case SSL_ERROR_NONE: 165b967cddfSBarry Smith break; 166b967cddfSBarry Smith case SSL_ERROR_ZERO_RETURN: 167b967cddfSBarry Smith SSL_shutdown(ssl); /* ignore shutdown error message */ 168b967cddfSBarry Smith break; 169b967cddfSBarry Smith case SSL_ERROR_SYSCALL: 170b967cddfSBarry Smith break; 171b967cddfSBarry Smith default: 172b967cddfSBarry Smith SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL read problem"); 173b967cddfSBarry Smith } 174b967cddfSBarry Smith buff[len] = 0; /* null terminate string */ 175b967cddfSBarry Smith ierr = PetscInfo1(NULL,"HTTPS result follows: \n%s\n",buff);CHKERRQ(ierr); 176b967cddfSBarry Smith 177b967cddfSBarry Smith SSL_free(ssl); 178b967cddfSBarry Smith ierr = PetscFree(request);CHKERRQ(ierr); 179b967cddfSBarry Smith PetscFunctionReturn(0); 180b967cddfSBarry Smith } 181b967cddfSBarry Smith 182b967cddfSBarry Smith #undef __FUNCT__ 183b967cddfSBarry Smith #define __FUNCT__ "PetscHTTPSConnect" 184b967cddfSBarry Smith PetscErrorCode PetscHTTPSConnect(const char host[],int port,SSL_CTX *ctx,int *sock,SSL **ssl) 185b967cddfSBarry Smith { 186b967cddfSBarry Smith BIO *sbio; 187b967cddfSBarry Smith PetscErrorCode ierr; 188b967cddfSBarry Smith 189b967cddfSBarry Smith PetscFunctionBegin; 190b967cddfSBarry Smith /* Connect the TCP socket*/ 191b967cddfSBarry Smith ierr = PetscOpenSocket(host,port,sock);CHKERRQ(ierr); 192b967cddfSBarry Smith 193b967cddfSBarry Smith /* Connect the SSL socket */ 194b967cddfSBarry Smith *ssl = SSL_new(ctx); 195b967cddfSBarry Smith sbio = BIO_new_socket(*sock,BIO_NOCLOSE); 196b967cddfSBarry Smith SSL_set_bio(*ssl,sbio,sbio); 197b967cddfSBarry Smith if (SSL_connect(*ssl) <= 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"SSL connect error"); 198b967cddfSBarry Smith PetscFunctionReturn(0); 199b967cddfSBarry Smith } 200b967cddfSBarry Smith 201